Programming Journal

学習したことの整理用です。

ransackを使って日付検索&プルダウン選択する

実装したいこと

掲示板一覧画面に、作成日で掲示板検索できる機能を実装したい

前提

ransack導入済み

実装の流れ

  • コントローラーにransack用の設定
  • ransackの検索条件をカスタムする
  • Viewに反映させる

Controller

def index
    @q = Board.ransack(params[:q])
    @boards = @q.result(distinct: true).includes(%i[user]).order(created_at: :desc).page(params[:page])
end

Custom Predicates

「2020年9月1日〜2020年9月3日までに作成された掲示板」のように日付を指定して掲示板を検索したいです。

ransack公式のpredicateリストの中から探してみます。

ransackのpredicateとは?

公式は、READ.MEだけでなくWikiも読むようにしないとダメですね。スルーしてました。
predecateは「述語」という意味です。例えば、contはcontainの略で、属性に「〜を含んでいる」ものを検索します。

The primary method of searching in Ransack is by using what is known as predicates. Predicates are used within Ransack search queries to determine what information to match. For instance, the cont predicate will check to see if an attribute called "first_name" contains a value using a wildcard query:
Basic Searching · activerecord-hackery/ransack Wiki · GitHub


gteq(greater then or equal to) 〜以上
lteq(less then or equal to) 〜以下

を使えば実装できそうですが、これで実装したところ、
「9月1日00時〜9月3日00時」までとなり、前日分の検索しかできませんでした。
「9月1日00時〜9月3日23時59分599999…」のような日付設定にしたいです。

公式のWikiに Ransackのpredecatesはカスタムできるよ、と例が書いてあります。
これで設定していきます。コメント部分は公式のコメントの翻訳です。

Custom Predicates · activerecord-hackery/ransack Wiki · GitHub

Ransack.configure do |config|
  config.add_predicate 'lteq_end_of_day',  #設定するpredicateに名前をつける
                      arel_predicate: 'lteq',  #使いたいpredicate
                      formatter: proc { |v| v.end_of_day } # 受け取った値をどうフォーマットするか
end

Arelとは

ArelはActive Recordの内部で使用されるSQL生成ライブラリです。

Arelでクエリを書くのはやめた方が良い5つの理由 - Qiita

end_of_day

end_of_dayっていきなり使ってるけど定義しなくていいの??と思ったら、
end_of_dayっていうメソッドがあるんですね。知らなかったです。

end_of_day() public Converts Date to a Time (or DateTime if necessary) with the time portion set to the end of the day (23:59:59) https://apidock.com/rails/Date/end_of_day

View

<%= f.date_field :created_at_gteq,
                  include_blank: true,
                  class: 'form-control'%>〜 #「〜」と書くと分かりやすい
<%= f.date_field :created_at_lteq_end_of_day, #さっき設定したやつ
                  include_blank: true,
                  class: 'form-control'%>

できあがり。

f:id:Study-Diary:20200906122738p:plain
日付検索

特に設定しなくてもカレンダー表示になった。Bootstrapがやってくれているのかな?謎

f:id:Study-Diary:20200906122816p:plain
カレンダー表示