Como tornar uma das associações “has_many: through” primária

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 PlaceCategoryRelationmesa e a primary_category_idcoluna Local> … que dor de cabeça!

Que tal um

has_one :primary_category

mas … está faltando alguma coisa … belongs_toem 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 PlaceCategoryRelationmodelo que apenas a categoria primária para um local seja definida como verdadeira.

Você definiu 2 associações em seu modelo, especificando class_nameuma e sourceoutra, 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_manyvez 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!