Aviso de descontinuação ao usar has_many: through: uniq no Rails 4

95

O Rails 4 introduziu um aviso de depreciação ao usar: uniq => true com has_many: through. Por exemplo:

has_many :donors, :through => :donations, :uniq => true

Rende o seguinte aviso:

DEPRECATION WARNING: The following options in your Goal.has_many :donors declaration are deprecated: :uniq. Please use a scope block instead. For example, the following:

    has_many :spam_comments, conditions: { spam: true }, class_name: 'Comment'

should be rewritten as the following:

    has_many :spam_comments, -> { where spam: true }, class_name: 'Comment'

Qual é a maneira correta de reescrever a declaração has_many acima?

Ryan Crispin Heneise
fonte

Respostas:

237

A uniqopção precisa ser movida para um bloco de escopo. Observe que o bloco de escopo precisa ser o segundo parâmetro para has_many(ou seja, você não pode deixá-lo no final da linha, ele precisa ser movido antes da :through => :donationsparte):

has_many :donors, -> { uniq }, :through => :donations

Pode parecer estranho, mas faz um pouco mais sentido se você considerar o caso em que há vários parâmetros. Por exemplo, este:

has_many :donors, :through => :donations, :uniq => true, :order => "name", :conditions => "age < 30"

torna-se:

has_many :donors, -> { where("age < 30").order("name").uniq }, :through => :donations
Dylan Markow
fonte
Obrigado, isso funciona muito bem! Onde você achou isso? Eu não consegui encontrar na documentação em lugar nenhum.
Ryan Crispin Heneise
6
Na verdade, eu vi no livro Upgrading to Rails 4 (está em andamento): upgradeingtorails4.com - não consegui encontrar em nenhum outro lugar.
Dylan Markow
1
@DylanMarkow o link para Atualizar para Rails 4 está extinto. O livro agora foi lançado sob uma licença CC em github.com/alindeman/upgradingtorails4
Ivar
1
Com Rails 5, use em distinctvez de uniq. Veja esta resposta para mais detalhes.
Nic Nilov
5

Além da resposta de Dylans, se você estiver estendendo a associação com um módulo, certifique-se de encadear no bloco de escopo (em vez de especificá-lo separadamente), assim:

has_many :donors,
  -> { extending(DonorExtensions).order(:name).uniq },
  through: :donations

Talvez seja só eu, mas parece muito pouco intuitivo usar um bloco de escopo para estender um proxy de associação.

Andrew Hacking
fonte