Portanto, você tem um modelo ActivreRecord com muitos para muitos tipos de associação com outro modelo:
class Place < ActiveRecord::Base
has_many :place_category_relations
has_many :categories, through: :place_category_relations
end
Mas agora que você tem muitas categorias, provavelmente deseja fazer uma principal para o seu objeto.
Você basicamente quer um
belongs_to :primary_category, class_name: 'Category'
mas para isso você precisa adicionar outra chave ao modelo Place. Uma migração, reforçando sincronizações entre a PlaceCategoryRelation
mesa e a primary_category_id
coluna Local> … que dor de cabeça!
Que tal um
has_one :primary_category
mas … está faltando alguma coisa … belongs_to
em algum lugar do modelo associado.
Portanto, você precisa de uma associação intermediária que atue como um para ::through =>
has_one
has_one :primary_category_relation, -> { where(is_primary: true) }, class_name: 'PlaceCategoryRelation'
Pronto, a maneira mais fácil no Rails de fazer isso é adicionar um sinalizador booleano no PlaceCategoryRelation
modelo que apenas a categoria primária para um local seja definida como verdadeira.
Você definiu 2 associações em seu modelo, especificando class_name
uma e source
outra, mas isso é muito poderoso, sem criar redundância:
class Place < ActiveRecord::Base
has_many :place_category_relations
has_many :categories, through: :place_category_relations
has_one :primary_category_relation, -> { where(is_primary: true) }, class_name: 'PlaceCategoryRelation'
has_one :primary_category, through: :primary_category_relation, source: :category
end
class PlaceCategoryRelation < ActiveRecord::Base
belongs_to :place
belongs_to :category
# Make sure only one category is primary per place
validates :is_primary, uniqueness: true, scope: :place_id
end
Esta solução eu encontrei depois de estar perto de escrever uma questão StackOverflow sobre qual é a melhor das 2 soluções propostas, que nenhuma era elegante como a que eu escrevi aqui. Antes de pressionar o botão “Fazer pergunta”, percebi uma pergunta semelhante , mas o modelo estava com em has_many
vez de has_many :through =>
, e então pesquisei no Google por “rails has_one conditions has many through”, que gerou a ideia mais próxima do que descrevi aqui.
Fique à vontade para fazer sugestões para melhorar isso, estou ansioso para saber mais!