環境
Rails 6.0.1
Ruby 2.6.3
PostgreSQL 11.16
状況
User
をPost
のcategory_id
の降順かつnil
を最後にソートしたいとき、このように書くと
User.eager_load(:posts)
.order('posts.category_id IS NULL')
.merge(Post.order(category_id: :desc))
.select('users.*', 'posts.category_id AS posts_category_id')
下記のエラーと
for SELECT DISTINCT, ORDER BY expressions must appear in select list
下記の警告が出る。
これについては伊藤さんの記事がとても参考になりました。
DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "posts.category_id IS NULL". Non-attribute arguments will be disallowed in Rails 6.1. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql().
エラー文についてはよくselect
にorder
したいカラムを指定すると解決するというようなことが書かれている事が多かったが、私の場合はすでに指定しているのにエラーが…。
解決法
降順でnil
を最後にソートするにはDESC NULLS LAST
を使う。
User.eager_load(:posts)
.order('posts.category_id DESC NULLS LAST')
.select('users.*', 'posts.category_id AS posts_category_id')
参考
Rails6.1からはnulls_first
とnulls_last
が使えるのですごく便利そう。