finding associations in sorted order

I have in my model

class Card < ActiveRecord::Base   has_many :idioms, dependent: :destroy end

class Idiom < ActiveRecord::Base   belongs_to :card end

In my schema, Idiom has an integer column kind. Given a certain card, I would like to have all associated idioms, but sorted in descending order according to the 'kind' column.

I could do a

  @card.idioms.sort { .... }

but would prefer doing the sorting by the time the data is retrieved from the database. I googled two suggestions:

(1) @card.idioms(:order => 'kind DESC')

This doesn't seem to have any effect.

(2) @card.idioms.all(:order => 'kind DESC')

This gives the error "wrong number of arguments (1 for 0)".

I think I could do a

Idiom.where(....)

and put an order restriction there, but I feel that Rails must have a way to specify sorting when following associations, and maybe I just made some silly mistake. Any ideas?

I have in my model

class Card < ActiveRecord::Base has_many :idioms, dependent: :destroy end

class Idiom < ActiveRecord::Base belongs_to :card end

In my schema, Idiom has an integer column kind. Given a certain card, I would like to have all associated idioms, but sorted in descending order according to the 'kind' column.

I could do a

@card.idioms.sort { .... }

but would prefer doing the sorting by the time the data is retrieved from the database. I googled two suggestions:

(1) @card.idioms(:order => 'kind DESC')

This doesn't seem to have any effect.

(2) @card.idioms.all(:order => 'kind DESC')

This gives the error "wrong number of arguments (1 for 0)".

I think I could do a

Idiom.where(....)

and put an order restriction there, but I feel that Rails must have a way to specify sorting when following associations, and maybe I just made some silly mistake. Any ideas?

It sounds to me as though maybe all of your idioms have the same value (or null) in their kind column. What does the database itself believe about these idioms? Have you tested that different values are being set for each? Also, what amount of data do you have?

Walter

What do you mean by not having any effect? It did not find anything, or they were not sorted correctly? If you have a look in log/development.log you will see the query being run and check that it looks ok.

Colin

Walter Davis wrote in post #1149912:

Colin Law wrote in post #1149914:

In my schema, Idiom has an integer column kind. Given a certain card, I (1) @card.idioms(:order => 'kind DESC')

This doesn't seem to have any effect.

What do you mean by not having any effect?

It means that they always come out in the same order (which, accidentally, is *ascending* according to the kind values, which is likely a consequence, that I create the Idiom objects with ascending kind values, and so the probability is high that - with my small development database - I just get them back in the order they were created.

BTW, I looked at the result by running .inspect on the returned data, and from this I found that it's not sorted descendingly.

If you have a look in log/development.log you will see the query being run and check that it looks ok.

Oh, of course, I should have thought of this myself! I'll do that next time I'm on the development host!

Ronald

Walter Davis wrote in post #1149912:

It sounds to me as though maybe all of your idioms have the same value (or null) in their kind column.

No, they have correct values (1, 2 and 3). Actually, the logic of the application ensures that there are only those values (I should this place into the model too).

Does it mean that in your opinion, my attempt to sort them would be correct?

Your code is correct: some_reference.order('kind DESC') is the correct way to get the order you are asking for. Remember that if you only have three possible values, the implicit sort of the members within each kind will probably be the ID, all other things being equal. You should see the same behavior as if you entered this explicitly:

  some_reference.order('kind DESC, id ASC')

Walter

?? Not, the OP originally posted:

  @card.idioms(:order => 'kind DESC')

which is 1) not equivalent, and 2) won't work.

Ooh, sorry, missed that whole side of the problem! Was that ever the way to do this, like say in Rails 1.5?

Walter

There is no "implicit" sort in SQL, the order within each kind will be indeterminate.

Hassan Schroeder wrote in post #1149926:

?? Not, the OP originally posted:

  @card.idioms(:order => 'kind DESC')

which is 1) not equivalent, and 2) won't work.

Oops!!!! I think that's it! Will check it on the next occasion.

(The OP is herewith ashamed)

Ronald

Thanks to all contributors! Hassan Schroeder's sharp eye finally spotted the culprit.

I have in my model

class Card < ActiveRecord::Base

has_many :idioms, dependent: :destroy

end

class Idiom < ActiveRecord::Base

belongs_to :card

end

In my schema, Idiom has an integer column kind. Given a certain card, I

would like to have all associated idioms, but sorted in descending order

according to the ‘kind’ column.

I could do a

@card.idioms.sort { … }

but would prefer doing the sorting by the time the data is retrieved

from the database. I googled two suggestions:

(1) @card.idioms(:order => ‘kind DESC’)
This doesn’t seem to have any effect.

This doesn’t do anything, because the association uses that single argument for something different (deciding whether to reload if already loaded).

(2) @card.idioms.all(:order => ‘kind DESC’)

This gives the error “wrong number of arguments (1 for 0)”.

I think I could do a

Idiom.where(…)

and put an order restriction there, but I feel that Rails must have a

way to specify sorting when following associations, and maybe I just

made some silly mistake. Any ideas?

There are a couple ways to do this, depending on how often you need the data sorted in a particular way:

  • adding an order onto your relation call will order the records:

@some_card.idioms.order(kind: :desc)

  • adding a scope will do the same thing:

class Idiom < ActiveRecord::Base

scope :by_kind, → { order(kind: :desc) }

end

@some_card.idioms.by_kind

  • or you can add the order directly to the association (building on the scope above):

class Card < ActiveRecord::Base

has_many :idioms, → { by_kind }, dependent: :destroy

end

@some_card.idioms # still sorted now

–Matt Jones