Advertencia obsoleta para Rails 4 has_many con pedido

105
class RelatedList < ActiveRecord::Base
  extend Enumerize

  enumerize :list_type, in: %w(groups projects)

  belongs_to :content
  has_many :contents, :order => :position

end

Tengo este modelo en mi aplicación de rieles que lanza una advertencia cuando trato de crear registros en la consola.

ADVERTENCIA DE DEPRECATION: Las siguientes opciones en su RelatedList.has_many: declaración de contenido están obsoletas:: order. En su lugar, utilice un bloque de alcance. Por ejemplo, lo siguiente: has_many: spam_comments, condiciones: {spam: true}, class_name: 'Comment' debe reescribirse como sigue: has_many: spam_comments, -> {where spam: true}, class_name: 'Comment'. (llamado desde /Users/shivam/Code/auroville/avorg/app/models/related_list.rb:7)

Parece que Rails 4 tiene una nueva sintaxis de orden para usar en modelos, pero parece que no puedo encontrar la documentación en Rails Guides.

Shankardevy
fuente

Respuestas:

250

En Rails 4, :orderha quedado obsoleto y debe reemplazarse con un bloque de alcance lambda como se muestra en la advertencia que ha publicado en la pregunta. Otro punto a tener en cuenta es que este bloque de alcance debe pasarse antes que cualquier otra opción de asociación, como dependent: :destroy etc.

Prueba esto:

has_many :contents, -> { order(:position) }

Para especificar la dirección del pedido, es decir, asco desccomo han sugerido @ joshua-coady y @wsprujit, use:

has_many :contents, -> { order 'position desc' }

o, usando el estilo hash:

has_many :contents, -> { order(position: :desc) }

Más referencias sobre ámbitos de registros activos parahas_many .

uve
fuente
3
funciona excelente! ¿Dónde puedo encontrar dicha información en las guías o documentos? No puedo encontrar uno. Gracias.
shankardevy
4
¿Qué pasa si tiene más de una opción obsoleta, digamos odery include? Esto: { order(:position), include(:track) }arroja un error en la coma.
kakubei
2
Para ordenar asc / desc, use-> { order(name: :asc) }
wspruijt
1
Si por alguna razón, solo desea que la colección se ordene algunas veces, también puede hacer lo list.contents.order('position desc')que puede ser más eficiente en general, y no como modelo intrusivo (en la respuesta votada, la lista conoce un campo de contenido, aquí el controlador lo sabe )
Dirty Henry
35

Me tomó un tiempo descubrir cómo ordenar e incluir, finalmente descubrí que encadena las declaraciones de alcance ,

has_many :things, -> { includes(:stuff).order("somedate desc") }, class_name: "SomeThing"
sfoop
fuente
2
Este era exactamente mi problema. Tratando de averiguar cómo ordenar una relación has_many por un atributo principal. No me di cuenta de que puedes hacer inclusiones como esta y luego ordenar. ¡Gracias!
timothyashaw
27

Solo pensé en agregar que si tiene alguna opción de argumentos hash, deben ir después de la lambda, así:

has_many :things, -> { order :stuff }, dependent: :destroy

Me tomó un minuto resolver esto por mí mismo; espero que ayude a cualquier otra persona que llegue a esta pregunta y tenga el mismo problema.

Wylliam Judd
fuente
3
Esto también es cierto para las asociaciones "a través" que podrían existir en el objeto -has_many :items, -> { order 'name' }, through: :suppliers
Major Major
0

Esto me funciona con Rails 4 y MongoDB

has_many :discounts, order: :min_amount.asc
Dave
fuente
-4

Alternativamente, puede poner la ordercláusula en el modelo, por ejemplo:

has_many :options, order: 'name' # In class Answer

Se convierte

has_many :options # In class Answer

default_scope { order 'name' } # In class Option

PD: lo tengo ArgumentError: wrong number of arguments (1 for 0)al hacer has_many :things, -> {}.

dorio
fuente
4
No use el alcance predeterminado. Si está acostumbrado a hacerlo, puede agregar más lógica a ese método mágico. Es difícil anularlo en el futuro.
Grzegorz Łuszczek