LoginSignup
5

More than 1 year has passed since last update.

【ransack】日付選択検索とプルダウン選択

Last updated at Posted at 2022-01-24

完成イメージ図

日付選択検索
Image from Gyazo

プルダウン選択
Image from Gyazo

前提

ransackenum/enum_helpの導入や設定をしていること。

【実装】日付選択検索

「◯◯月◯◯日〜◯◯月◯◯日」のようにするため、predicate(述語)を使っていく。

predicate(述語)とはransackを使った検索フォームで使用できる検索述語のこと。cont(部分一致)_eq(イコール)に該当する。

「◯◯月◯◯日〜◯◯月◯◯日」を文章で表すと、
「◯◯月◯◯日 以上 ◯◯月◯◯日 以下 」、つまり記号で表すと
「◯◯月◯◯日 ◯◯月◯◯日 」になる。

 はより大きいか等しい、述語だと_gteqに該当する。
 はより小さいか等しい、述語だと_lteqに該当する。

_gteq_lteqを使ってコードに表記してみる。

search.html.rb
<%= search_form_for @search, url: admin_users_path do |f| %> 
 <%= f.date_field :created_at_gteq%>
 <span>~</span>
 <%= f.date_field :created_at_lteq%>
<%end%>

しかし上記のコードで、1月1日〜1月7日まで検索をかけても、1月7日分は表示されない。
SQLを見てみると

SELECT COUNT(DISTINCT "boards"."id") FROM "boards" WHERE ("boards"."created_at" >= '2022-01-01 00:00:00' AND "boards"."created_at" <= '2022-01-07 00:00:00')

実際に検索された条件は「’2022-01-01 00:00:00′ から ‘2022-01-07 00:00:00まで」

つまり、「2022/01/07」の前日分(2022/01/06)までしか検索されていないことになっている。
欲しいのは、2022/01/07 23:59:59までのが必要なのでこれでは取得できない。

欲しい日の 23:59:59までが取得できるように、predicate(述語)をカスタムする必要がある。

predicate(述語)をカスタム

config/initializers/ransack.rbを作成し、以下を記述していく。

config/initializers/ransack.rb
Ransack.configure do |config|
    config.add_predicate 'lteq_end_of_day',
                    arel_predicate: 'lteq',
                    formatter: proc { |v| v.end_of_day }
end

config.add_predicate
  述語の名前を定義

arel_predicate
  カスタムの元にするpredicateを指定

formatter: proc { |v| v.end_of_day }
  end_of_dayメソッドを実行している。
  
proc
  ブロックをオブジェクト化する働きがある。この場合だと、
  { |v| v.end_of_day }ここの処理をひとかたまりとしてprocに落とし込んでいる。

end_of_day
  end_of_dayメソッドは、その日の最後の時点 (23:59:59) のタイムスタンプを返す。

predicate(述語)を設定したら、先程のコードを修正すると、「’2022-01-01 00:00:00′ から ‘2022-01-07 23:59:59まで」のデータが抽出される。

search.html.rb
<%= search_form_for @search, url: admin_users_path do |f| %> 
 <%= f.date_field :created_at_gteq%>
 <span>~</span>
 <%= f.date_field :created_at_lteq_end_of_day%>
<%end%>

【実装】プルダウン選択

search.html.rb
<%= search_form_for @search, url: admin_users_path do |f| %> 
 <%= f.select :role_eq, User.roles_i18n.invert.map{|key, value| [key, User.roles[value]]}, { include_blank: "指定なし" }%>
<%end%>

#f.selectの基本形
<%= f.select :保存されるカラム名, [ ["表示される文字","保存される値"], ["表示される文字","保存される値"], {オプション}, {htmlオプション} ] %>

User.roles_i18n.invert
  User.roles_i18nによって{"general" => "一般", "admin" => "管理者" }というハッシュを取得している。

  しかしf.selectの基本の形を見てみると、["表示される文字","保存される値"]となっているため、
  .invertを使い、{"一般" => "general", "管理者" => "admin" }に変換する。

.map{|key, value| [key, User.roles[value]]}
  mapメソッドを使ってハッシュの要素の数だけ、ブロック内で処理を繰り返して新しい配列を返している。

ransackenumで定義した文字列に対応しておらず、保存される値のvalueを01などのintegerで渡す必要がある。その際にUser.roles[value]が役立つ。

include_blank
  include_blankオプションは、先頭に表示されるメッセージに空白行を表示するオプション。

参考記事

[Rails] ransackを使った日時範囲検索
[Rails] enum_helpよる多言語対応とransackを使ってプルダウン検索機能を実装

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5