7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rails + Ransack + Postgresql で NULL を含むカラムのソート

Last updated at Posted at 2015-09-05

やりたいこと

  • Rails+Postgresqlの環境で、ransackのsort_linkを使ってソートを実装している。
  • PostgresqlはDESCでソートするとNULLが先頭にきてしまう。NULLを後方に並べたい。
  • ORDER BY (number IS NULL), number DESC というかんじのクエリを組み立てたい。

こうなった

user.rb
scope :reorder_by_is_null, ->(column, direction) { select('*', "(#{column} IS NULL) AS is_null").reorder('is_null', column => direction) }
users_controller.rb
  def index
    @q = User.ransack(params[:q])
    @users = @q.result(distinct: true).reorder_by_is_null(sort_column, sort_direction)
    # => SELECT DISTINCT *, (id IS NULL) AS is_null FROM "users" ORDER BY is_null, "users"."id" ASC
  end

  private

  def sort_column
    User.column_names.include?(sort_params[:column]) ? sort_params[:column] : 'id'
  end

  def sort_direction
    %w(asc desc).include?(sort_params[:direction]) ? sort_params[:direction] : 'asc'
  end

  def sort_params
    return {} if params[:q].blank? || params[:q][:s].blank?
    s = params[:q][:s].split(' ')
    { column: s[0], direction: s[1] }
  end

reorder_by_is_null

  • Ransackにより ORDER BY column direction というクエリが作られてしまうため、reorder で上書きする必要がある。
  • DISTINCTするとSELECTにないカラムをORDER BYに指定できないため、SELECT に (column IS NULL) AS is_null を付け加えている。

sort_params

  • sort_linkを使うと :q => { :s => "id asc" } みたいなパラメータが来るので、カラム名とASC/DESCに分けて取り出している。

sort_column, sort_direction

  • sort_linkでソートパラメータが設定されたない場合のデフォルトのORDER BYが id ASC になるようにしてある。

そして

  • とりあえず意図した通りにソートされるようになった。
  • もっと良いやり方ありそう。
7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?