Help us understand the problem. What is going on with this article?

検索用のgem"Ransack"の簡易チュートリアルが書き上がってしまったので公開する

More than 1 year has passed since last update.

検索用のgem "ransack"

ransackはrailsで非常に簡単に検索機能を追加することができるgemです。
whereですぐ書けるような簡単な検索から、複雑な組み合わせの検索まで広く実装可能です。

導入

Gemfileに ransack を追加します。

/Gemfile
gem 'ransack'

追記したらbundle installを実行しましょう。

いざ実装!!

前提

今回はUserを検索する機能を作成すると想定します。
Userモデルは、

$ rails g scaffold Users name gender age:integer birthday:date

で作成したことにします。

え?
birthdayを登録しているならageはいらないだろって??

That's right.
でも機能を紹介するために使うので目を瞑っていただきます。あしからず。

また、今回はbootstrapを導入しているという程で進みます。
と言ってもform-groupform-inlineを使用して見栄えを良くしているだけなので、導入していなくても問題ないはずです。

また、参考までに筆者の環境を提示しておくと、

$ rails -v
Rails 5.0.3
$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]

こんな感じです。

Controller

まず、検索機能を追加したいcontrollerを変更。
今回の例では、/app/controllers/users_controller.rbのusers#indexを変更します。

/app/controllers/users_controller.rb
class UserController < ApplicationController
  def index
    @search = User.search(params[:q])
    @users = @search.result
  end
end

controller側はこれだけでOK。ボブもびっくり。ね、簡単でしょ?

View

Search Form

次にフォームを設置したいのでviewをいじります。
今回はscaffoldで作成した前提なので、<table> ~ </table>の前にでも設置しましょう。

/app/views/users/index.html.erb
<%= search_form_for @search do |f| %>
  <div class="form-group">
    <%= f.label :name_cont, "Name" %>
    <%= f.text_field :name_cont, class: "form-control" %>
  </div>
  <div class="actions"><%= f.submit "Search" %></div>
<% end %>

名前の検索が実装できているはずです。
実際にrails sしてhttp://localhost:3000から見てみましょう。

他のフォームについては後述。

Sort

次に並び替えの機能を実装させます。
例えば<th>Name</th>の部分をクリックすると名前の昇順・降順で表示を変えられるようにする、アレですね。
ここでは、名前と年齢で並び替えができるようにします。

/app/views/users/index.html.erb
  <tr>
    <th><%= sort_link(@search, :name, "Name") %></th>
    <th>Gender</th>
    <th><%= sort_link(@search, :age, "Age") %></th>
    <th>Birthday</th>
  </tr>

変更したら保存してrails sで実際に見てみましょう。

その他の検索フォーム作成方法

検索フォームは先程の

<%= search_form_for @search do |f| %> ~ <% end %>

内に記述することで、条件を組み合わせた検索が可能になります。

文字列編

まずは、主に名前やコメント・プロフィール等の文字列に対して行う検索方法のよく使うであろうものをピックアップします。

部分一致 _cont(contain)

例で使用したものになります。名前などを部分一致で絞り込む際に使用できます。

完全一致 _eq(equal)

先程の名前検索フォーム、

<%= f.label :name_cont, "Name" %>

_contの部分を_eqつまり、

<%= f.label :name_eq, "Name" %>

とすることで完全一致のレコードのみを表示できるようになります。
性別をドロップダウンリスト等にして男女で絞りこめるようにするなどにも使えますね。

OR検索 _cont_any (contains any)

OR検索には_cont_anyを使用します。
こちらも同様に

<%= f.label :name_cont_any, "Name" %>

と修正するだけです。
以後、この修正箇所は省略します。

数値編

次に、数値で検索を掛ける場合によく使用するものを取り上げます。
ここまでは文字列の検索が主だったためtext_fieldを用いていましたが、数値の検索を行うためnumber_fieldを用いるようにしましょう。
今回はageの値を使用するので、

/app/views/users/index.html.erb
<%= search_form_for @search do |f| %>
  <div class="form-group">
    <%= f.label :name_cont, "Name" %>
    <%= f.text_field :name_cont, class: "form-control" %>
  </div>
  <div class="form-group">
    <%= f.label :age_lt, "Age" %>
    <%= f.number_field, class: "form-control" :age_lt %>
  </div>
  <div class="actions"><%= f.submit "Search" %></div>
<% end %>

のように記述すると良いと思います。

○○未満 _lt (less than)

みんなだいすき未成年を検索したい時に使
年齢で用いることはあまりないかもしれませんが、ノルマ未達成の人を絞り込むだとか、販売目標以下の商品だけを表示したい、などの用途で用いることがある(のかな?わからない)のが_ltです。

未成年を検索したい時にも使えまゲフンゲフン!!!

数値編で最初に記述した例がこれになっていますね。

○○以下 _lteq (less than or equal to)

こちらは「未満」じゃなくてその値も含んだ範囲内を知りたいんじゃボケって時に使います。

○○以上、○○より大きい

「以下」ではなく「以上」で検索したい場合は、ltの部分をgtにしてを用います。"greater than"の略ですね。
これで「○○以上」、「○○より大きい」の値も検索することが可能になりました。

範囲検索

ここまででは「○以上」、「○以下」単体でした。
次は両方を同時に、つまり、
「○以上 ●以下」の値を検索する時のフォームの作り方です。
と言っても、たいしたことはしないです。次のコードを見てください。

/app/views/users/index.html.erb
  <div class="form-inline">
    <%= f.label :Age %>
      <%= f.number_field :age_gteq, class: "form-control"%>以上 ~
      <%= f.number_field :age_lteq, class: "form-control" %>以下
  </div>

見ての通り、ふたつを組み合わせただけですね。

これで「15歳以上 18歳以下」のJKを絞り込むことができる、と思ったら大間違いです!
この条件だと、「中学3年生(未JK)」または「JKだったもの」をギリギリ含んでしまいます。

でも安心してください、そのための"Birthday"です

例: 日付で検索

「未JK」及び「だったもの」を表示させないために、xxxx/04/01 ~ yyyy/03/31生まれで絞り込みたいとします。いや、みんなきっと絞り込みたいはずです。
ほとんどrailsの仕様の話になってしまいますが、日付で検索する場合はdate_selectを用います。

/app/views/users/index.html.erb
  <div class="form-inline">
    <%= f.label :Birhtday %>
    <%= f.date_select :birthday_gteq, {include_blank: true, use_month_numbers: true, date_separator: ' / '}, class: "form-control" %><%= f.date_select :birthday_lteq, {include_blank: true, use_month_numbers: true, date_separator: ' / '}, class: "form-control" %>
  </div>

これでバッチリですね。

ただひとつ注意点として、これだと男子高校生もヒットしてしまうので、実装する歳は性別もしっかり絞り込めるようにしましょう。

最後に

JK検索は冗談として、日付の絞り込みは使用頻度も高いと思います。
より細かい条件や生成されるSQL文について気になる方はwiki( https://github.com/activerecord-hackery/ransack/wiki/basic-searching )をご覧ください。

初めは自分用のメモとして書き始めたのですが、完全に導入用の手抜きチュートリアルになってしまいました。
提示している例はテストせずアドリブで書いているため、間違っている部分があったらご指摘をお願い致します。

また、筆者はrails歴も浅く開発実績も全くなザコ大学生ですので、アドバイス等も頂けると大変うれしいです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした