问题
I have a ranking which shows the fastest User:
@users = User.find.sort { |a, b| b.finished_at <=> a.created_at }
Now I hat to add some code to prevent getting an error because of finished_at beeing nil
until the user finished.
@users = User.find(:all, :conditions => "finished_at IS NOT NULL").sort { |a, b| b.finished_at <=> a.created_at }
But sort
doesn't work. Is this way of chaining methods flawed? And is find(:all, :conditions => "finished_at IS NOT NULL")
the rails 3 way or outdated?
Thanks in advance
回答1:
The rails 3 way to query this would be:
@users = User.where('finished_at IS NOT NULL')
As for the sort, yes, it's ok to chain like that. A simple sort, where it was all on a single field, would be better in sql:
@users = User.where('finished_at IS NOT NULL').order(:finished_at)
However, your sort does something weird, comparing one field on the left and another on the right. I don't think your sort algorithm is going to work right, as it will depend on the initial record order. Since you are comparing apples to oranges, it's not going to be consistent.
You said "the fastest user", which makes me think you really want the time difference between the created_at and finished_at times:
@users = User.where('finished_at IS NOT NULL').
sort {|a,b| (a.finished_at - a.created_at) <=> (b.finished_at - b.created_at)
If you want to let rails 3 lazy load that, however, you have to sort in the sql, instead of in ruby. This should work in mysql I think:
@users = User.where('finished_at IS NOT NULL').
select('users.*, timediff(finished_at,created_at) AS duration').
order('duration')
This way, the query won't be executed until values are actually called for, which helps if you need page caching. You also have the benefit of having the duration available:
@users[0].duration
来源:https://stackoverflow.com/questions/6440039/rails-3-sort-after-where-condition-using-not-null