Tbpgr Blog

Employee Experience Engineer tbpgr(てぃーびー) のブログ

Ruby on Rails | 一覧のソート

概要

一覧のソート

詳細

一覧のソート機能を実装します。

サンプル

仕様

テーブル構造の一覧のヘッダーにあるリンクをクリックすると
昇順降順を切り替えてソートする。
アイコンはKickstartを使用。
単一項目によるソートのみ対応。

page.js.coffee

Coffee Scriptの共通処理としてソート用のメソッドを追加。
submit直前にhiddenにソート対象のカラムと昇順降順を指定しています。
この処理は後ほど作成するソートリンクから呼び出します。

class @Page
  # other logic

  @sort_submit: (sort, order, form) ->
    document.getElementById('sort').value = sort
    document.getElementById('order').value = @next_order order
    form.submit()

  @next_order: (order) ->
    return "asc" if order is "desc"
    return "desc" if order is "asc"
    return "asc" if order is "none"
views/user/list.html.haml

一覧のフォームの中にhiddenでsortとorderを追加します。
テーブルヘッダーに、ソートリンクを設定するヘルパーを指定します。
ヘルパーの詳細はapplication_helper参照
※抜粋

  =hidden_field_tag :sort, @sort
  =hidden_field_tag :order, @order

  / その他の処理

  = content_tag :th, :id => "id" do
    = link_to_sort "/user/search", "user", "id", @sort, @order
  = content_tag :th, :id => "login" do
    = link_to_sort "/user/search", "user", "login", @sort, @order
controllers/user/user_controller.rb

user_controllerが単数形なのは命名間違えただけなのでスルー希望・・・。
画面初期表示のアクション時はソート指定無しで固定にするため、sort・orderにnoneを設定。
ソートリンクからはsearchアクションを呼び出す想定。

sortアクションで実際にソートを指定しています。
ActiveRecord::Baseをオープンして処理を追加したので実処理は
config/initializers/active_record.rbを参照
※抜粋

def index(user, notice, sort, order)
  @users = User.all
  @user ||= User.new
  @notice = notice
  @sort = "none"
  @order = "none"
  layout_settings main_menu: true, user_menu: true
end

def search(user, sort, order)
  @sort = sort
  @order = order
  set_user_input user
  search_user user, @sort, @order
  layout_settings main_menu: true, user_menu: true
  render :action => 'index' 
end

private
def search_user(user, sort, order)
  @users ||= User.login_is(user[:login])
                .name_is(user[:name])
                .email_is(user[:email])
                .admin_is(user[:admin])
                .deleted_is(user[:deleted]).order_by(sort, order)
models/user/users.rb

scopeとしてソートを定義。実処理はActiveRecord::Baseをオープンしてメソッドを追加しています。

class User < ActiveRecord::Base
  scope :order_by, order_by
  # other logic
end
conf/initializer/active_record.rb
module ActiveRecord
  class Base
    class << self
      # other logic
      def order_by()
        lambda {|sort, order|
          next if sort == "none" || order == "none"
          order("#{sort} #{order}")
        } 
      end
    end
  end
end
application_helper.rb
def link_to_sort(url, model, column, sort, order)
  # taraは自作のヘルパーで、実際はt('activerecord.attributes.model.column')を呼び出しているだけです
  label = tara(model, column)
  link_to url, :onclick => "Page.sort_submit('#{column}', '#{order}', $(this).closest('form'))", method: :post do
    "<i class=\"icon-#{order_style(order.to_s, sort, column)}\">#{label}</i>".html_safe
  end
end

画像

ソート前

名前で昇順ソート

名前で降順ソート