LoginSignup
11
6

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を使ってプルダウン検索機能を実装

11
6
0

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
  3. You can use dark theme
What you can do with signing up
11
6