Skip to content

Instantly share code, notes, and snippets.

@ismarsantos
Created June 3, 2025 17:11
Show Gist options
  • Save ismarsantos/629f053035a696ed203c308a0fd1e92a to your computer and use it in GitHub Desktop.
Save ismarsantos/629f053035a696ed203c308a0fd1e92a to your computer and use it in GitHub Desktop.
# 1. Migration para criar a tabela associativa polimórfica
# db/migrate/xxxx_create_categorizations.rb
class CreateCategorizations < ActiveRecord::Migration[7.2]
def change
create_table :categorizations do |t|
t.references :category, null: false, foreign_key: true
t.references :categorizable, polymorphic: true, null: false
t.timestamps
end
add_index :categorizations, [:categorizable_type, :categorizable_id]
add_index :categorizations, [:category_id, :categorizable_type, :categorizable_id], unique: true, name: 'index_categorizations_unique'
end
end
class Category < ApplicationRecord
has_many :categorizations, dependent: :destroy
has_many :amenities, through: :categorizations, source: :categorizable, source_type: 'Amenity'
has_many :plans, through: :categorizations, source: :categorizable, source_type: 'Plan'
validates :name, presence: true, uniqueness: true
end
# 3. Model Categorization (tabela associativa)
# app/models/categorization.rb
class Categorization < ApplicationRecord
belongs_to :category
belongs_to :categorizable, polymorphic: true
validates :category_id, uniqueness: { scope: [:categorizable_type, :categorizable_id] }
end
# 4. Model Amenity
# app/models/amenity.rb
class Amenity < ApplicationRecord
has_many :categorizations, as: :categorizable, dependent: :destroy
has_many :categories, through: :categorizations
validates :name, presence: true
end
# 5. Model Plan
# app/models/Plan.rb
class Plan < ApplicationRecord
has_many :categorizations, as: :categorizable, dependent: :destroy
has_many :categories, through: :categorizations
validates :name, presence: true
end
# 6. Exemplos de uso no console/controller
# Criar categorias
core = Category.create!(name: 'Core Amenities')
basic = Category.create!(name: 'Spa')
outdoor = Category.create!(name: 'Outdoor')
# Criar amenities e plans
pool = Amenity.create!(name: 'Swimming Pool')
gym = Amenity.create!(name: 'Gym')
studio = Plan.create!(name: 'Studio')
loft = Plan.create!(name: 'Loft')
# Associar categorias
pool.categories << [core, outdoor]
gym.categories << core
studio.categories << basic
loft.categories << core
# Consultas
core.amenities # => [pool, gym]
core.plans # => [loft]
pool.categories # => [core, outdoor]
# Método para buscar categorias por tipo
def categories_for_type(type)
case type.downcase
when 'amenity'
Category.joins(:categorizations)
.where(categorizations: { categorizable_type: 'Amenity' })
.distinct
when 'Plan'
Category.joins(:categorizations)
.where(categorizations: { categorizable_type: 'Plan' })
.distinct
end
end
# 7. Concern para facilitar reutilização (opcional)
# app/models/concerns/categorizable.rb
module Categorizable
extend ActiveSupport::Concern
included do
has_many :categorizations, as: :categorizable, dependent: :destroy
has_many :categories, through: :categorizations
end
def add_category(category)
categories << category unless categories.include?(category)
end
def remove_category(category)
categories.delete(category)
end
def categorized_as?(category_name)
categories.exists?(name: category_name)
end
end
# Para usar o concern, substitua has_many nos models por:
# include Categorizable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment