So, I have the following scope in my Photo model:
scope :best, order(:average_rating.desc)
The only problem is, the ratings were added to t
Try this :)
scope :best, order("average_rating DESC NULLS LAST")
Well, I never found an approach that would work across DB drivers, so I just forced the value of all the records that were previously nil to be zero. That solved it for me, although it was a bit brutish. When the timer runs out I'll accept this since it is the solution I used, but if anyone revisits this and wants to provide an alternative answer in the future I'll be happy to accept a different answer later on.
while the coalesce
SQL method is great, if your database does not support this, here is a method that should be supported along all databaseses:
order("-average_rating DESC")
This will order your records and put the NULL
to the end.
I know this was awhile ago but wouldn't this work across a few
order("ISNULL(average_rating) DESC")
I'm a bit late to the game but this just came up again and the solution really isn't that difficult.
A portable solution is to use a CASE to turn NULLs into something that will go to the end. If your ratings are non-negative, then -1 is a good choice:
order('case when average_rating is null then -1 else average_rating end desc')
Using COALESCE instead will work in many databases and is a lot less noisy than a CASE:
order('coalesce(average_rating, -1) desc')
If you wanted an ASC sort then the above approaches would put NULLs at the beginning. If you wanted them at the end then you'd use something bigger than your highest rating instead of -1. For example, if you rated things from one to five, you could use 11 to replace NULLs:
order('case when average_rating is null then 11 else average_rating end asc')
order('coalesce(average_rating, 11) asc')
Most people would use 10 but sometimes you need to get a little bit louder so ours go to 11.
You can't really depend on the database putting NULLs at the beginning or end so it is best to be explicit even if you're just reminding your future-self that you've handled the NULL case already.