🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby on Rails 5

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

Q&A

解決済

1回答

1044閲覧

Rails scopeを使用した際の複数ワード検索機能の実装方法

yupapapa

総合スコア24

Ruby on Rails 5

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

0グッド

0クリップ

投稿2019/11/25 10:44

編集2019/11/26 07:43

railsであいまい検索機能を実装しています。そこで、空白による複数ワードでの検索機能を実装したいのですが、うまくいきません。

ワード検索機能は現在、他の詳細検索とまとめて、form_withの中の一部としてあります。
さらに、それらはmodelでscopeを使用しているため、複数ワードの処理をどこに記述すればい良いのかがわかりません。
以前実装した時は、ワード検索のみだったのでcontroller内に複数ワード機能を記述していたのですが、今回は上記の通り、model内でscopeを使用しているので、組み立て方がわからずお手上げ状態です。
scopeを使用する場合は、複数ワード機能のような普通controller内で記述するコードはどのようにして記述すれば良いのですか?
ご教授よろしくお願いします。

<%= form_with(scope: :search, url: search_posts_path, method: :get, local: true) do |f| %> <div class="details-p">詳細検索</div> <div class="serach-label"><i class="fas fa-plus my-grew fa-fw fa-lg"></i><%= f.label :キーワードを追加する %></div> <%= f.text_field :name, value: @search_params[:name], class: "search-text" %> <div class="serach-label"><i class="fas fa-coins my-grew fa-fw fa-lg"></i><%= f.label :価格%></div> <%= f.number_field :price_from,placeholder: "¥ Min", value: @search_params[:price_from], class: "search-number" %> ~ <%= f.number_field :price_to, placeholder: "¥ Max", value: @search_params[:price_to], class: "search-number" %> <div class="serach-label"><i class="fas fa-list my-grew fa-fw fa-lg"></i><%= f.label :カテゴリー %></div> <%= f.select :category, [["メンズ", "メンズ"], ["レディース", "レディース"],["ホビー", "ホビー"],["ゲーム", "ゲーム"],["家電", "家電"],["インテリア", "インテリア"],["グッズ", "グッズ"],["スポーツ", "スポーツ"],["その他", "その他"]],{ selected: @search_params[:category] }, { class: "search-category"}%> <div class="serach-label"><i class="fas fa-band-aid my-grew fa-fw fa-lg"></i><%= f.label :商品の状態 %></div> <div class="status-list"> <%= f.check_box :status, {multiple: true, include_hidden: true}, '新品',nil %> <%= f.label :新品 %> <div class="status-list-li"> <%= f.check_box :status, {multiple: true, include_hidden: true}, '目立った傷や汚れなし',nil %> <%= f.label :目立った傷や汚れなし %> </div> <div class="status-list-li"> <%= f.check_box :status, {multiple: true, include_hidden: true}, '傷や汚れあり',nil %> <%= f.label :傷や汚れあり %> </div> <%= f.check_box :status, {multiple: true, include_hidden: true}, '全体的に状態が悪い',nil %> <%= f.label :全体的に状態が悪い %> </div> <div class="btn-box"> <div class="clear-button"><%= link_to "クリア", search_posts_path %></div> <%= f.submit '完了', class: "search-button" %> </div> <% end %>
def search @search_params = post_search_params @posts = Post.search(@search_params).order(sort) end private def post_search_params params.fetch(:search, {}).permit(:name,:price_from, :price_to,:category,status: []) end

postrb

1 scope :search, -> (search_params) do 2 return if search_params.blank? 3 4 name_like(search_params[:name]) 5 .price_from(search_params[:price_from]) 6 .price_to(search_params[:price_to]) 7 .category_like(search_params[:category]) 8 .status_like(search_params[:status]) 9 end 10 11 scope :name_like, -> (name) { where('name LIKE ?', "%#{name}%") if name.present? } 12 scope :price_from, -> (from) { where('? <= price', from) if from.present? } 13 scope :price_to, -> (to) { where('price <= ?', to) if to.present? } 14 scope :category_like, -> (category) { where(category: category) if category.present? } 15 scope :status_like, -> (status) { where(status: status) if status.present? }

ここから追記

def search sort = params[:sort] || "created_at DESC" @posts_else = Post.all.order(sort) @search_params = post_search_params #@posts = Post.search(@search_params).order(sort) end
<div class="search-body"> <% @posts_else.each do |post| %> <%= link_to post_path(post.id) do %> <div class="search-container"> <div class="index-price">¥<%= converting_to_jpy(post.price) %></div> <div class="index-image"><%= image_tag post.image.url %></div> <div class="index-name"><%= truncate(post.name, length: 20) %></div> </div> <% end %> <% end %> </div> </div> <% end %>

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

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

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

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

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

guest

回答1

0

ベストアンサー

そうむずかしく考えることはないです。scopeはそこに書かれた(最後の)式が検索式に追加される、ぐらいの意味です。
scope :name_like, -> (name) { where('name LIKE ?', "%#{name}%") if name.present? }
の {}内に、「controller内に複数ワード機能を記述していた」のをいれてみて下さい。
最後の式が where() とか whereの chain になるようにして。
if は if..endにくくったほうが書きやすいでしょう。

投稿2019/11/25 21:46

winterboum

総合スコア23567

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

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

yupapapa

2019/11/26 07:43 編集

scope :name_like, -> (name) { words = params[:name].to_s.gsub(/(?:[[:space:]%_])+/, " ").split(" ") query = (["name LIKE ?"] * words.size).join(" AND ") @posts = Post.search(@search_params).order(sort).where(query, *words.map{|w| "%#{w}%"}) if name.present? } このように追加してみたのですが、検索機能が機能しなくなってしまいました(エラーは出てない) どこか間違っているのでしょうか? (controller内の@postsはコメントアウトしています)
yupapapa

2019/11/26 07:45 編集

因みに、検索すると@posts_elseの処理(追記しました)が表示されます。(本来は検索したワードのpostが存在しない場合に表示される)
winterboum

2019/11/26 08:12

中身はきちんと吟味していませんが、動いていたということですからそのまま写すとこんな感じでしょうか。 scope :name_like, -> (name) { if name.present? words =name.to_s.gsub(/(?:[[:space:]%_])+/, " ").split(" ") query = (["name LIKE ?"] * words.size).join(" AND ") where(query,*words.map{|w| "%#{w}%"}) } end
yupapapa

2019/11/26 08:34

無事実装できました!! このように{}内にも処理を描くことができるのですね。 Rails初心者なので試行錯誤しても自分で解決できず行き詰まってしまうことが多いので、いつも回答してくださり感謝します。
winterboum

2019/11/26 09:37

大抵の言語がそうなっていますが、「最後の式の結果」が意味を持ちます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問