112
class RelatedList < ActiveRecord::Base
  extend Enumerize

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

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

end

I have this model in my rails app which throws warning when I try to create records in console.

DEPRECATION WARNING: The following options in your RelatedList.has_many :contents declaration are deprecated: :order. 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' . (called from at /Users/shivam/Code/auroville/avorg/app/models/related_list.rb:7)

It seems like Rails 4 has new :order syntax for use in models but I can't seem to find the documentation in Rails Guides.

James Mason
  • 4,246
  • 1
  • 21
  • 26
shankardevy
  • 4,290
  • 5
  • 32
  • 49

5 Answers5

257

In Rails 4, :order has been deprecated and needs to be replaced with lambda scope block as shown in the warning you've posted in the question. Another point to note is that this scope block needs to be passed before any other association options such as dependent: :destroy etc.

Give this a try:

has_many :contents, -> { order(:position) } # Order by :asc by default

To specify order direction, i.e. either asc or desc as @joshua-coady and @wsprujit have suggested, use:

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

or, using the hash style:

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

Further reference on Active Record Scopes for has_many.

Christopher Oezbek
  • 23,994
  • 6
  • 61
  • 85
vee
  • 38,255
  • 7
  • 74
  • 78
  • 3
    works superb! where can I find such information in the guides or docs? I can't find one. thanks. – shankardevy Aug 17 '13 at 02:59
  • 1
    [Info on order scope in the guides](http://guides.rubyonrails.org/association_basics.html#scopes-for-has-many-order) – Josh Coady Oct 15 '13 at 02:33
  • 6
    What about if you have more than one deprecated option, say `oder` and `include`? This: `{ order(:position), include(:track) }` throws error on the comma. – kakubei Nov 15 '13 at 10:02
  • 2
    For ordering asc/desc, use `-> { order(name: :asc) }` – wspruijt Feb 25 '14 at 13:44
  • 1
    If for some reason, you just want the collection to be ordered some times, you can also do `list.contents.order('position desc')` which can be more efficient overall, and not as model intrusive (in the voted answer, list knows a field of content, here the controller knows it) – Mick F May 27 '15 at 14:38
  • This gives me an error "syntax error, unexpected '\n', expecting =>" - - but there is no "=>" using the new method, stated here. Using wspruijt's version, I get the error, "syntax error, unexpected tLABEL ... , -> { order (created_at: :desc) }". Pity the older, clearer syntax is now dumped by Rails 4 in favor of this gibberish. Seems if you have any other conditions, they must all go into some curly-bracket spasm, or you can't do ordered-sorts on the model, anymore. – JosephK Jun 06 '15 at 09:32
38

It took me a while to figure out how to do order and include, I eventually found that you chain the scope statements,

has_many :things, -> { includes(:stuff).order("somedate desc") }, class_name: "SomeThing"
sfoop
  • 532
  • 4
  • 8
  • 2
    This was exactly my issue. Trying to figure out how to order a has_many relationship by a parent attribute. Didn't realize you can do includes like this and then order. Thanks! – timothyashaw Nov 11 '17 at 19:51
31

Just thought I'd add that if you have any option hash arguments, they have to go after the lambda, like this:

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

Took me a minute to figure this out myself - hopefully it helps anyone else coming to this question having the same problem.

Wylliam Judd
  • 9,935
  • 2
  • 26
  • 36
0

This works for me with Rails 4 & MongoDB

has_many :discounts, order: :min_amount.asc
Dave
  • 4,376
  • 3
  • 24
  • 37
-4

Alternatively, you can put the order clause on the model, for instance:

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

Becomes

has_many :options # In class Answer

default_scope { order 'name' } # In class Option

PS: I got ArgumentError: wrong number of arguments (1 for 0) when doing has_many :things, -> {}.

Dorian
  • 22,759
  • 8
  • 120
  • 116