Advertencia de obsolescencia al usar has_many: through: uniq en Rails 4

95

Rails 4 ha introducido una advertencia de obsolescencia al usar: uniq => true con has_many: through. Por ejemplo:

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

Produce la siguiente advertencia:

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'

¿Cuál es la forma correcta de reescribir la declaración has_many anterior?

Ryan Crispin Heneise
fuente

Respuestas:

237

La uniqopción debe moverse a un bloque de alcance. Tenga en cuenta que el bloque de alcance debe ser el segundo parámetro has_many(es decir, no puede dejarlo al final de la línea, debe moverse antes de la :through => :donationsparte):

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

Puede parecer extraño, pero tiene un poco más de sentido si considera el caso en el que tiene varios parámetros. Por ejemplo, esto:

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

se convierte en:

has_many :donors, -> { where("age < 30").order("name").uniq }, :through => :donations
Dylan Markow
fuente
Gracias, esto funciona muy bien. ¿Dónde encontraste esto? No he podido encontrarlo en la documentación en ninguna parte.
Ryan Crispin Heneise
6
De hecho, lo vi en el libro Upgrading to Rails 4 (está en progreso): upgradingtorails4.com - no he podido encontrarlo en ningún otro lugar.
Dylan Markow
1
@DylanMarkow, el enlace para actualizar a Rails 4 está inactivo. El libro ahora se ha publicado bajo una licencia CC en github.com/alindeman/upgradingtorails4
Ivar
1
Con Rails 5 use en distinctlugar de uniq. Consulte esta respuesta para obtener más detalles.
Nic Nilov
5

Además de la respuesta de Dylans, si está extendiendo la asociación con un módulo, asegúrese de encadenarlo en el bloque de alcance (en lugar de especificarlo por separado), así:

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

Tal vez sea solo yo, pero parece muy poco intuitivo usar un bloque de alcance para extender un proxy de asociación.

Andrew Hacking
fuente