ransackを利用した日付指定での検索方法

[ransack]Gemを利用した日付指定での検索方法

下記のように日付を指定しての検索方法の実装方法になります

Image from Gyazo

フィールドにカレンダー機能を付与する場合は、以下のように[f.date_field]を利用する

Image from Gyazo

[app/views ファイル]

    <%= search_form_for @q, url: admin_boards_path do |f| %>
      <%= f.search_field :title_or_body_cont, class: 'form-control mr-3', placeholder: t('defaults.search_word') %>
      <%= f.date_field :created_at_gteq, class: 'form-control' %>
      〜
      <%= f.date_field :created_at_lteq, class: 'form-control' %>
        <%= f.submit class: 'btn btn-primary' %>
    <% end %>

[ransack]Gemを使って日付指定での検索を実装する際に以下のように記述するとうまくいかない。

[app/controllers ファイル]

  def index
    @q = Board.ransack(params[:q])
    @boards = @q.result(distinct: true).includes(:user).order(created_at: :desc).page(params[:page])
  end
[app/views ファイル]

    <%= search_form_for @q, url: admin_boards_path do |f| %>
      <%= f.search_field :title_or_body_cont, class: 'form-control mr-3', placeholder: t('defaults.search_word') %>
      <%= f.date_field :created_at_gteq, class: 'form-control' %>
      〜
      <%= f.date_field :created_at_lteq, class: 'form-control' %>
        <%= f.submit class: 'btn btn-primary' %>
    <% end %>

上記のように記述すると以下のように検索をかけても7/11の分が検索結果に出てこない

Image from Gyazo

サーバーのログを確認してみると以下のようになっている

Image from Gyazo

[7/10 0時0分]〜[7/11 0時0分]の検索になってしまっている
実際に検索をかけたいのは、[7/10 0時0分]〜[7/11 23時59分]である

[ransack]Gemに元々備えられているMatchersを利用しても上記のようなPredicate([7/11 23時59分]という条件)は、実現できないので自分でPredicateをカスタマイズする必要がある。

Predicateをカスタマイズする方法は、[config/initializers/ransack.rb]に以下のような記述をして各設定をする(下記の記述は、[ransack]GemのGitHubWikiのCustom Predicatesの欄に記載がある)

[config/initializers/ransack.rb]

Ransack.configure do |config|
  config.add_predicate 'equals_diddly',    # Predicateの名前を設定

    arel_predicate: 'eq',    #  どんな動きをするかを設定(カスタマイズしたいpredicateを指定)

    formatter: proc { |v| "#{v}-diddly" },    #  検索で入力されるフォーマットをこのブロック内で自分で自由に変える

    validator: proc { |v| v.present? },   #  バリデーションで値を検証する。無効な値は、検索に使用されない

    compounds: true,   #  これは恐らく複数のarel_predicateの組み合わせをtrueにするかということ。デフォルトではtrueになっており、基本的にはいじらなくてOK

    type: :string,  #  与えられた値をここで設定した型に変換する。基本的には、DBのカラムのタイプを設定する<br>

    case_insensitive: true   #  大文字と小文字を区別する設定(デフォルトではfalseになっている)
end

今回のように[7/10 0時0分]〜[7/11 23時59分]というような検索をするためのPredicateのカスタマイズと検索フィールドの記述は、以下のようになる

[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_of_dayメソッドを利用することで23時59分までが対象になる
                       validator: proc { |v| v.present? },
                       compounds: true,
                       type: :datetime,
                       case_insensitive: true
end
[app/views ファイル]

    <%= search_form_for @q, url: admin_boards_path do |f| %>
      <%= f.search_field :title_or_body_cont, class: 'form-control mr-3', placeholder: t('defaults.search_word') %>
      <%= f.date_field :created_at_gteq, class: 'form-control' %>
      〜
      <%= f.date_field :created_at_lteq_end_of_day, class: 'form-control' %>  # カスタマイズした[lteq_end_of_day]のPredicateを利用
        <%= f.submit class: 'btn btn-primary' %>
    <% end %>

※ポイント
Predicate: Ransackの検索クエリの中で、どのような情報をマッチさせるかを決定するために使用される
end_of_day: レシーバの日付の23時59分59秒を返す

※ハマったこと
ransackを使って検索フォームに値を入力して検索をかけると以下のエラーになる

Image from Gyazo

スキーマでテーブル名が以下のようにUsersと大文字になっていたのが原因 Image from Gyazo

参考記事:

【Rails】日付入力フォームをカレンダー式にしたい(date型, datetime型) - Qiita

ransackを使った日付検索 - 学習記録

【Rails】custom predicateについて(ransack) - bokuの学習記録

Railsの日時を操作するメソッドたち - Re: 醤油の一升瓶じゃあ戦えない