読者です 読者をやめる 読者になる 読者になる

Ransack を使って簡単検索フォーム作成

はじめに

検索機能を実装するために gem を作っていたんだけど、 何を思ったか検索フォームを実装する gem を Google 先生に質問してしまい、 Ransack という gem を知ってしまった。

自作の gem より高機能そうだったんで、ライバル調査という名目で試してみた。

Ransack のインストール

Gemfile に下記を追加し、bundle を実行。

gem "ransack"

検索機能の実装

検索対象のモデルを用意
class Product < ActiveRecord::Base
  attr_accessible :name, :description, :price
  has_many :comments
end

class Comment < ActiveRecord::Base
  attr_accessible :product_id, :username, :body, :rate
  belongs_to :product
end
コントローラーを修正

search メソッドと result メソッドが使えるようになっている。

class ProductsController < ApplicationController
  ...

  def index
    # 検索フォームの入力内容で検索する
    @q = Product.search(params[:q])

    # 重複を排除
    @products = @q.result(distinct: true)
  end

  ...
end

params にキー q が存在しないときは全データ取得していた。

ビューに検索フォームを配置

search_form_for という検索フォームを作成するためのヘルパが提供されている。

<%= search_form_for @q do |f| %>
  <div class="control-group">
    <%= f.label :name_cont %>
    <div class="controls">
      <%= f.text_field :name_cont %>
    </div>
  </div>

  <div class="control-group">
    <%= f.label :price_gteq %>
    <div class="controls">
      <%= f.number_field :price_gteq %>
    </div>
  </div>

  <div class="control-group">
    <%= f.label :price_lteq %>
    <div class="controls">
      <%= f.number_field :price_lteq %>
    </div>
  </div>

  <%= f.submit %>
<% end %>

使い方は form_for とたいして変わらない。

たったこれだけで実装完了

ブラウザで表示してみる。

f:id:griefworker:20130618203627p:plain

price の範囲を入力して Search をクリック。

f:id:griefworker:20130618203644p:plain

おお、ちゃんと絞り込まれてるね。

アソシエーションにも対応していた

検索フォームを次のように作成すると、 belongs_to や has_many で関連付けているモデルの属性も使って 検索できた。

<%= search_form_for @q do |f| %>
  <div class="control-group">
    <%= f.label :comments_username_cont %>
    <div class="controls">
      <%= f.text_field :comments_username_cont %>
    </div>
  </div>

  <%= f.submit %>
<% end %>

こいつはスゴイ。

まとめ

Ransack を使えば Rails アプリに検索機能を簡単に実装できた。 値の一致だけでなく、比較や、値を含むかどうかでも検索でき、 さらにアソシエーションにも対応しているという高機能っぷり。 ユーザーの入力でモデルを検索するだけなら、Ransack 使えば十分だな。

似たような gem を作っていたけど、機能はだいぶ Ransack が上。 ピボットが必要かなぁ。