検索用のgem "ransack"
ransackはrailsで非常に簡単に検索機能を追加することができるgemです。
whereですぐ書けるような簡単な検索から、複雑な組み合わせの検索まで広く実装可能です。
導入
Gemfileに ransack を追加します。
gem 'ransack'
追記したらbundle install
を実行しましょう。
いざ実装!!
前提
今回はUserを検索する機能を作成すると想定します。
Userモデルは、
$ rails g scaffold Users name gender age:integer birthday:date
で作成したことにします。
え?
birthdayを登録しているならageはいらないだろって??
That's right.
でも機能を紹介するために使うので目を瞑っていただきます。あしからず。
また、今回はbootstrapを導入しているという程で進みます。
と言ってもform-group
やform-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を変更します。
class UserController < ApplicationController
def index
@search = User.search(params[:q])
@users = @search.result
end
end
controller側はこれだけでOK。ボブもびっくり。ね、簡単でしょ?
View
Search Form
次にフォームを設置したいのでviewをいじります。
今回はscaffoldで作成した前提なので、<table> ~ </table>
の前にでも設置しましょう。
<%= 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>
の部分をクリックすると名前の昇順・降順で表示を変えられるようにする、アレですね。
ここでは、名前と年齢で並び替えができるようにします。
<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
の値を使用するので、
<%= 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"の略ですね。
これで「○○以上」、「○○より大きい」の値も検索することが可能になりました。
範囲検索
ここまででは「○以上」、「○以下」単体でした。
次は両方を同時に、つまり、
「○以上 ●以下」の値を検索する時のフォームの作り方です。
と言っても、たいしたことはしないです。次のコードを見てください。
<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
を用います。
<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歴も浅く開発実績も全くなザコ大学生ですので、アドバイス等も頂けると大変うれしいです。