質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

2回答

2874閲覧

【Ruby Rails5】条件分岐でwhereを変えたい

fujita222

総合スコア14

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2018/12/21 07:03

Rails勉強中です。

ユーザの入力した検索条件によって、whereメソッドを変える場合の正しい書き方について教えてください。

ユーザが検索条件を入力して、それに応じた結果を一覧で返す画面を作っています。

検索条件(今回はparams[:search])の各パラメータの有無でwhereメソッドを複数、使いたいです。

具体的にはBoardモデルにおいて、Board.title、Board.updated_atによる絞り込み条件を付けたいです。

・ユーザが入力した検索条件にtitleがあればタイトルによるLIKE検索
・ユーザが入力した検索条件に更新日があれば更新日による絞り込み

というようにIFの条件によって検索条件を追加したい場合の書き方が分かりません。

実際に書いてるソースコードは下記です。

Ruby

1#app/models/board.rb 2scope :mypage_search, ->(user_id, search_params = {}) do 3 4 board = Board.where(user_id: user_id) 5 board = board.where("title LIKE %?%", search_params[:title]) if search_params[:title] 6 7 if search_params[:updated_at] 8 9 if search_params[:updated_at] == 1 10 board = board.where("updated_at > ?", Time.zone.datetime.strftime('%Y%m%d 00:00:00')) 11 12 elseif earch_params[:updated_at] == 3 13 board = board.where("updated_at > ?", 3.day.ago) 14 15 elseif earch_params[:updated_at] == 7 16 board = board.where("updated_at > ?", 7.day.ago) 17 end 18 19 end 20 binding.pry 21 22 end

これだと実行されるSQLが

SQL

1SELECT `boards`.* FROM `boards` WHERE `boards`.`user_id` = 3 AND (title LIKE %'dsfaga'%)

のようにANDの後にある変な()が付いたりしてうまくいきません。

詳しい方、正しい書き方を教えていただけないでしょうか?

ちょっと説明が下手な感じがしてますが。。^^;
詳しい方、お手数ですがよろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

ANDの後にある変な()が付いたりしてうまくいきません。

いえ、問題はカッコではなく(数式と同じで、WHEREの条件にカッコが多くても正常に動作します)、LIKEへの引数です。

?のプレースホルダに入れられるのは1つの値なので、%?%としても動作しません。LIKEの特殊文字列をエスケープするという問題はありますが、とりあえずboard.where("title LIKE ?", "%#{search_params[:title]}%")というように%込みにした文字列を?に流し込む、という方法を取るのがいいでしょう。

投稿2018/12/21 07:12

編集2018/12/21 07:12
maisumakun

総合スコア145184

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fujita222

2019/01/05 10:10

ご回答ありがとうございました! 解決できました。
guest

0

ソースコードを全部見られるわけではないので雰囲気ですが: 次のようにもう少し細かく「何をするか」でグループ分けをしてあげると、「scope メソッドのチェインで全体を表す」といった書き方が出来るようになるかもしれません

ruby

1class Board < ActiveRecord::Base 2 scope :mypage_search, ->(user_id, search_params = {}) do 3 where(user_id: user_id) 4 .find_by_board_title(search_params[:title]) 5 .find_by_update_date(search_params[:updated_at]) 6 end 7 8 scope :find_by_update_date, ->(updated_at) do 9 return all if updated_at.nil? 10 11 case updated_at 12 when 1 13 # NOTE: この経路はエラーメッセージが表示されて動かない 14 where('updated_at > ?', Time.zone.datetime.strftime('%Y%m%d 00:00:00')) 15 when 3, 7 16 where('updated_at > ?', updated_at.day.ago) 17 else 18 all 19 end 20 end 21 22 scope :find_by_board_title, ->(title) do 23 return all if title.nil? 24 25 where('title LIKE ?', "%#{title}%") 26 end 27end

ruby

1Board.mypage_search(1, title: 'foo', updated_at: 7) 2# Board Load (2.6ms) SELECT "boards".* FROM "boards" WHERE "boards"."user_id" = 1 AND (title LIKE '%foo%') AND (updated_at > '2018-12-22 05:21:26.771 3136') 4# => #<Board::ActiveRecord_Relation:0x2b276b437778>

「もし値があれば検索する」処理は scope メソッドと組み合わせてのガード節 (eg. return all if updated_at.nil? ) が有効かもしれません

(あと、もしかしたら、わたしが追加した scope メソッドの命名はもう少し考えた方が よりわかり易しく 実際に使う際にすぐ理解できるものとして 扱えるようになるかもしれません)

何か参考になれば幸いです

投稿2018/12/29 05:39

gouf

総合スコア2321

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fujita222

2019/01/05 10:12

ご回答ありがとうございました たしかにこの実装のほうがコントローラー側がスッキリしていいですね 参考になりました。 ありがごうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問