fluid_27’s blog

勉強した内容をアウトプットするためのブログ

scopeを使って、絞り込み検索機能を実装してみた

raiils の初学者です。

scopeについてよく分かってなかったのですが、絞り込み検索機能を実装するにあたって、「scope使えば実装できるかも」となって、実際に使ってみたので、まとめたいと思います。

 

 

 scopeを使うことになった経緯

そもそも今までは絞り込み検索機能はwhereを使ってDBからデータを絞って取り出せばいいや。と考えていました。

ただ、絞り込む要素がいくつかあったとして、そのうちのどれかをユーザーが選択しなかった場合の処理。

 

ようは下の写真のように

f:id:fluid_27:20210602184352p:plain

 

「開始日付」、「終了日付」、「開始時刻」、「終了時刻」、「方面」、「駅」

と絞り込み要素が複数存在した場合の絞り込み型として

@posts = Post.where('date => ?', params[:post][:start_date]).where('date =< ?', params[:post][:end_date]).where('date => ?', [:post][:start_time])・・・

といった感じでwhereをつなげてしまうと、

「今回は 開始日付と 終了日付 だけで絞り込みたい」のような一部だけの絞り込みというのが出来ず、どの項目も必ず選択することになってしまいます。

 

以前、同じような状況に陥った際に

if params[:post][:start_date]

 ・・・

 

というように、if文で分岐させて、if文の中にwhereを使った絞り込み処理をしていたのですが、今回のように項目が多いとif文がめちゃ長くなってしまいます。

 

そこでググってみると、scopeを使って絞り込み検索機能を実装出来そうだったのでscopeを使ってみました。

 

そもそもscopeって?

「なんかmodelにvalidation設定する際に使ったことあったけど、結局何?」 となったのですが、ようは

scopeを使えば、where、joins、includesなどの複数クエリをまとめて、1つのメソッドとして定義できる

 ということみたいです。(違ったらごめんなさい)

 

scopeを使うと良いこと

scope1つに1つにif文をつけられるので、 paramsに値が入ってない場合は(ユーザーが全項目を選択してなくても)

「全選択」扱いにすることができました。

以下が実際に書いたコードです。

 

実際に書いたコード

Post.rb

# 検索の際の期間絞り込み

scope :s_duration, ->(start_date) { where("date >= ?", start_date) if start_date.present? }

scope :e_duration, ->(end_date) { where("date <= ?", end_date) if end_date.present? }

 

# 検索の際の時間絞り込み scope :s_time, ->(start_time) { where("time >= ?", start_time) if start_time.present? }

scope :e_time, ->(end_time) { where("time >= ?", end_time) if end_time.present? }

 

# 検索の際の方面と駅の絞り込み scope :direction, ->(direction) { where("direction = ?", direction) if direction.present? }

scope :station, ->(station) { where("station_id = ?", station) if station.present? }

 

post.controller.rb

def posts_search

  s_time = params[:post][:start_time]

  e_time = params[:post][:end_time]

  s_date = params[:post][:start_date]

  e_date = params[:post][:end_date]

  direction = params[:post][:direction]

  station = params[:post][:station]

  @posts = Post.s_duration(s_date).e_duration(e_date).s_time(s_time).e_time(e_time).direction(direction).station(station)

end

 

本当はもっと短く書けるのかもしれませんが、今回はこれで良しとしました。

詳しくはrailsのサイトに載っています。

 

 参考サイト

https://qiita.com/ozin/items/24d1b220a002004a6351

https://railsguides.jp/active_record_validations.html