Rails with RANSACK
前回の投稿でなんとか、CRUDの基本的なところまでModal Formを使用した構成で実現できました!
今回は、登録・更新されたテーブルに対して、一覧検索機能をつけたいと思いました。
要件
- 一覧画面に一覧検索機能を付加する
- 検索要件
- User.id:完全一致
- User.name:前方後方部分一致
- User.created_at:以上・以下範囲検索
- User.updated_at:以上・以下範囲検索
なぜRANSACK?
Google先生に「Rails 一覧検索」みたいな感じでお伺いを立てましたが、当たり前ですが、ActiveRecordの#where()であったり、を書かなくてはならないようでした。確かにそれでも問題ないのですが、SQLをなるべくなら書きたくないということで、漁ったところRANSACKというGemに出会いました。
いざRANSACK
では導入してみましょう
Gemfile
Gemfile
gem 'ransack'
と記載し、
terminal
$ bundle install
しましょう。
form.html.erb
form.html.erb
<%= search_form_for @q do |f| %>
<div class="form-group">
<%= f.label :name_cont, "name", class: "font-weight-bold" %>
<%= f.search_field :name_cont, class: "form-control" %>
</div>
<%= f.submit sanitize('<i class="fa fa-search"></i> Search'), class: "btn btn-dark" %>
<% end %>
注意点として
- form_forの代わりにsearch_form_forを使用すること
- [カラム名]_[検索条件]で検索条件を指定します。
検索条件の指定
_eq
User.ransack(name_eq: "test").result
# SELECT users.* FROM users WHERE users.name = 'test';
_not_eq
User.ransack(name_not_eq: "test").result
# SELECT users.* FROM users WHERE users.name != 'test';
_matches
User.ransack(name_matches: "test").result
# SELECT users.* FROM users WHERE users.name LIKE 'test';
User.ransack(name_matches: "test%").result
# SELECT users.* FROM users WHERE users.name LIKE 'test%';
_does_not_match
User.ransack(name_does_not_match: "test").result
# SELECT users.* FROM users WHERE users.name NOT LIKE 'test';
_matches_any
User.ransack(name_matches_any: "test").result
# SELECT users.* FROM users WHERE ( users.name LIKE 'test' );
User.ransack(name_matches_any: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name LIKE 'test' OR users.name LIKE 'hoge' );
_matches_all
User.ransack(name_matches_all: "test").result
# SELECT users.* FROM users WHERE ( users.name LIKE 'test' );
User.ransack(name_matches_all: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name LIKE 'test' AND users.name LIKE 'hoge' );
_does_not_match_any
User.ransack(name_does_not_match_any: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name NOT LIKE 'test' OR users.name NOT LIKE 'hoge' );
_does_not_match_all
User.ransack(name_does_not_match_all: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name NOT LIKE 'test' AND users.name NOT LIKE 'hoge' );
_lt
User.ransack(created_at_lt: "2019-01-01 00:00:00").result
# SELECT users.* FROM users WHERE users.created_at < '2019-01-01 00:00:00';
_lteq
User.ransack(created_at_lteq: "2019-01-01 00:00:00").result
# SELECT users.* FROM users WHERE users.created_at <= '2019-01-01 00:00:00';
_gt
User.ransack(created_at_gt: "2019-01-01 00:00:00").result
# SELECT users.* FROM users WHERE users.created_at > '2019-01-01 00:00:00';
_gteq
User.ransack(created_at_gteq: "2019-01-01 00:00:00").result
# SELECT users.* FROM users WHERE users.created_at >= '2019-01-01 00:00:00';
_present
User.ransack(name_present: 1).result
# SELECT users.* FROM users WHERE ( users.name IS NOT NULL AND users.name != '' );
# _presentは文字列のカラムのみ使用可能(NOT NULLかつ非空文字)
_blank
User.ransack(name_blank: 1).result
# SELECT users.* FROM users WHERE ( users.name IS NULL OR users.name = '' );
# _blankはNULLまたは空文字
_null
User.ransack(name_null: 1).result
# SELECT users.* FROM users WHERE users.name IS NULL;
_not_null
User.ransack(name_not_null: 1).result
# SELECT users.* FROM users WHERE users.name IS NOT NULL;
_in
User.ransack(name_in: "test").result
# SELECT users.* FROM users WHERE users.name IN ( 'test' );
User.ransack(name_in: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE users.name IN ( 'test', 'hoge' );
_not_in
User.ransack(name_not_in: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE users.name NOT IN ( 'test', 'hoge' );
_lt_any
User.ransack(created_at_lt_any: ["2019-01-01 00:00:00", "2018-01-01 00:10:00"]).result
# SELECT users.* FROM users WHERE ( users.created_at < '2019-01-01 00:00:00' OR users.created_at < '2018-01-01 00:10:00' )
_lteq_any
User.ransack(created_at_lteq_any: ["2019-01-01 00:00:00", "2018-01-01 00:10:00"]).result
# SELECT users.* FROM users WHERE ( users.created_at <= '2019-01-01 00:00:00' OR users.created_at <= '2018-01-01 00:10:00' );
_gt_any
User.ransack(created_at_gt_any: ["2019-01-01 00:00:00", "2018-01-01 00:10:00"]).result
# SELECT users.* FROM users WHERE ( users.created_at > '2019-01-01 00:00:00' OR users.created_at > '2018-01-01 00:10:00' )
_gteq_any
User.ransack(created_at_gteq_any: ["2019-01-01 00:00:00", "2018-01-01 00:10:00"]).result
# SELECT users.* FROM users WHERE ( users.created_at >= '2019-01-01 00:00:00' OR users.created_at >= '2018-01-01 00:10:00' );
_matches_any
User.ransack(name_matches_any: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name LIKE 'test' OR users.name LIKE 'hoge' );
_lt_all
User.ransack(created_at_lt_all: ["2019-01-01 00:00:00", "2018-01-01 00:10:00"]).result
# SELECT users.* FROM users WHERE ( users.created_at < '2019-01-01 00:00:00' AND users.created_at < '2018-01-01 00:10:00' );
_lteq_all
User.ransack(created_at_lteq_all: ["2019-01-01 00:00:00", "2018-01-01 00:10:00"]).result
# SELECT users.* FROM users WHERE ( users.created_at <= '2019-01-01 00:00:00' AND users.created_at <= '2018-01-01 00:10:00' );
_gt_all
User.ransack(created_at_gt_all: ["2019-01-01 00:00:00", "2018-01-01 00:10:00"]).result
# SELECT users.* FROM users WHERE ( users.created_at > '2019-01-01 00:00:00' AND users.created_at > '2018-01-01 00:10:00' );
_gteq_all
User.ransack(created_at_gteq_all: ["2019-01-01 00:00:00", "2018-01-01 00:10:00"]).result
# SELECT users.* FROM users WHERE ( users.created_at >= '2019-01-01 00:00:00' AND users.created_at >= '2018-01-01 00:10:00' );
_matches_all
User.ransack(name_matches_all: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name LIKE 'test' AND users.name LIKE 'hoge' );
_does_not_match_all
User.ransack(name_does_not_match_all: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name NOT LIKE 'test' AND users.name NOT LIKE 'hoge' );
_start
User.ransack(name_start: "test").result
# SELECT users.* FROM users WHERE users.name LIKE 'test%';
_not_start
User.ransack(name_not_start: "test").result
# SELECT users.* FROM users WHERE users.name NOT LIKE 'test%';
_start_any
User.ransack(name_start_any: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name LIKE 'test%' OR users.name LIKE 'hoge%' );
_start_all
User.ransack(name_start_all: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name LIKE 'test%' AND users.name LIKE 'hoge%' );
_not_start_any
User.ransack(name_not_start_any: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name NOT LIKE 'test%' OR users.name NOT LIKE 'hoge%' );
_not_start_all
User.ransack(name_not_start_all: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name NOT LIKE 'test%' AND users.name NOT LIKE 'hoge%' );
_end
User.ransack(name_end: "test").result
# SELECT users.* FROM users WHERE users.name LIKE '%test';
_not_end
User.ransack(name_not_end: "test").result
# SELECT users.* FROM users WHERE users.name NOT LIKE '%test';
_end_any
User.ransack(name_end_any: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name LIKE '%test' OR users.name LIKE '%hoge' );
_end_all
User.ransack(name_end_all: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name LIKE '%test' AND users.name LIKE '%hoge' );
_not_end_any
User.ransack(name_not_end_any: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name NOT LIKE '%test' OR users.name NOT LIKE '%hoge' );
_not_end_all
User.ransack(name_not_end_all: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name NOT LIKE '%test' AND users.name NOT LIKE '%hoge' );
_cont
User.ransack(name_cont: "test").result
# SELECT users.* FROM users WHERE users.name LIKE '%test%' ;
_cont_any
User.ransack(name_cont_any: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name LIKE '%test%' OR users.name LIKE '%hoge%' );
_cont_all
User.ransack(name_cont_all: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name LIKE '%test%' AND users.name LIKE '%hoge%' );
_not_cont
User.ransack(name_not_cont: "test").result
# SELECT users.* FROM users WHERE users.name NOT LIKE '%test%' ;
_not_cont_any
User.ransack(name_not_cont_any: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name NOT LIKE '%test%' OR users.name NOT LIKE '%hoge%' );
_cont_all
User.ransack(name_not_cont_all: ["test", "hoge"]).result
# SELECT users.* FROM users WHERE ( users.name NOT LIKE '%test%' AND users.name NOT LIKE '%hoge%' );
_true
_false