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