Aviso preterido para Rails 4 has_many com pedido

105
class RelatedList < ActiveRecord::Base
  extend Enumerize

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

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

end

Eu tenho este modelo em meu aplicativo rails que lança um aviso quando tento criar registros no console.

AVISO DE DEPRECAÇÃO: As seguintes opções em sua declaração RelatedList.has_many: contents estão obsoletas:: order. Em vez disso, use um bloco de escopo. Por exemplo, o seguinte: has_many: spam_comments, conditions: {spam: true}, class_name: 'Comentário' deve ser reescrito como o seguinte: has_many: spam_comments, -> {where spam: true}, class_name: 'Comment'. (chamado em /Users/shivam/Code/auroville/avorg/app/models/related_list.rb:7)

Parece que o Rails 4 tem uma nova: sintaxe de ordem para uso em modelos, mas não consigo encontrar a documentação nos Guias do Rails.

Shankardevy
fonte

Respostas:

250

No Rails 4, :orderestá obsoleto e precisa ser substituído pelo bloco de escopo lambda, conforme mostrado no aviso que você postou na pergunta. Outro ponto a ser observado é que este bloco de escopo precisa ser passado antes de quaisquer outras opções de associação, como dependent: :destroy etc.

Experimente:

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

Para especificar a direção do pedido, ou seja, ascou desccomo @ joshua-coady e @wsprujit sugeriram, use:

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

ou, usando o estilo hash:

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

Outras referências sobre escopos Active Record parahas_many .

vee
fonte
3
funciona excelente! onde posso encontrar essas informações nos guias ou documentos? Não consigo encontrar um. obrigado.
Shankardevy
4
E se você tiver mais de uma opção obsoleta, digamos odere include? Este: { order(:position), include(:track) }lança um erro na vírgula.
kakubei
2
Para pedir asc / desc, use-> { order(name: :asc) }
wspruijt
1
Se por algum motivo, você deseja apenas que a coleção seja ordenada algumas vezes, você também pode fazer o list.contents.order('position desc')que pode ser mais eficiente no geral, e não como um modelo intrusivo (na resposta votada, a lista conhece um campo de conteúdo, aqui o controlador o conhece )
Dirty Henry
35

Levei um tempo para descobrir como fazer o pedido e incluir, acabei descobrindo que você encadeia as declarações de escopo ,

has_many :things, -> { includes(:stuff).order("somedate desc") }, class_name: "SomeThing"
sfoop
fonte
2
Este foi exatamente o meu problema. Tentando descobrir como ordenar um relacionamento has_many por um atributo pai. Não sabia que você pode fazer inclusões como essa e depois fazer o pedido. Obrigado!
timothyashaw
27

Apenas pensei em acrescentar que, se você tiver qualquer opção de argumentos de hash, eles devem ir depois do lambda, assim:

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

Levei um minuto para descobrir isso sozinho - espero que ajude qualquer pessoa que tenha o mesmo problema com essa pergunta.

Wylliam Judd
fonte
3
Isso também é verdadeiro para associações "através de" que podem existir no objetohas_many :items, -> { order 'name' }, through: :suppliers
Maior Maior
0

Isso funciona para mim com Rails 4 e MongoDB

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

Alternativamente, você pode colocar a ordercláusula no modelo, por exemplo:

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

Torna-se

has_many :options # In class Answer

default_scope { order 'name' } # In class Option

PS: Eu tenho ArgumentError: wrong number of arguments (1 for 0)ao fazer has_many :things, -> {}.

Dorian
fonte
4
Não use o escopo padrão. Se você está acostumado a fazer isso, pode adicionar mais lógica a esse método mágico. É difícil substituí-lo no futuro.
Grzegorz Łuszczek de