Rails 3 сортирует после условия .where, используя NOT NULL - PullRequest
3 голосов
/ 22 июня 2011

У меня есть рейтинг, который показывает самый быстрый пользователь:

@users = User.find.sort { |a, b| b.finished_at <=> a.created_at }

Теперь я хочу добавить некоторый код, чтобы предотвратить ошибку из-за того, что Finish_at работает nil до тех пор, пока пользователь не закончит работу.

@users = User.find(:all, :conditions => "finished_at IS NOT NULL").sort { |a, b| b.finished_at <=> a.created_at }

Но sort не работает. Является ли этот способ создания цепочек некорректным? И find(:all, :conditions => "finished_at IS NOT NULL") рельсы 3 пути или устарели?

Заранее спасибо

1 Ответ

14 голосов
/ 22 июня 2011

У рельсов есть 3 способа сделать запрос:

@users = User.where('finished_at IS NOT NULL') 

Что касается сортировки, да, все в порядке, чтобы так цеплять. Простая сортировка, где все было бы в одном поле, была бы лучше в sql:

@users = User.where('finished_at IS NOT NULL').order(:finished_at)

Однако ваш тип делает что-то странное, сравнивая одно поле слева и другое справа. Я не думаю, что ваш алгоритм сортировки будет работать правильно, так как он будет зависеть от начального порядка записи. Поскольку вы сравниваете яблоки с апельсинами, это не будет последовательным.

Вы сказали "самый быстрый пользователь", что заставляет меня думать, что вы действительно хотите разницу во времени между временами созданного и завершенного:

@users = User.where('finished_at IS NOT NULL').
              sort {|a,b| (a.finished_at - a.created_at) <=> (b.finished_at - b.created_at)

Если вы хотите, чтобы rails 3 загружалась лениво, то вам нужно отсортировать в sql, а не в ruby. Это должно работать в MySQL, я думаю:

@users = User.where('finished_at IS NOT NULL').
              select('users.*, timediff(finished_at,created_at) AS duration').
              order('duration')

Таким образом, запрос не будет выполнен до тех пор, пока значения не будут фактически вызваны, что помогает, если вам необходимо кэширование страницы. Вы также можете воспользоваться доступной продолжительностью:

@users[0].duration
...