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

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

詳細はこちら
Ruby on Rails 6

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

Q&A

解決済

2回答

1440閲覧

ransackを用いた検索機能

shawn_709

総合スコア13

Ruby on Rails 6

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

0グッド

0クリップ

投稿2021/02/14 09:30

ご回答いただけるとありがたいです。よろしくお願いします!

###アプリ概要
勉強の問題をシェアするアプリを作っています。ユーザーはコンテンツ(「学年・教科・カテゴリー・問題・答え・解説」を入力)を投稿することができます。トップページでは自分のコンテンツのみが表示されます。他ユーザーのユーザー詳細ページに遷移すれば、そのユーザーが投稿したコンテンツを見ることができます。
検索機能を使えば、該当するコンテンツのみを表示させることができます。

実現したいこと

ユーザー1の詳細ページでキーワード検索をしたら、ユーザー1の該当するコンテンツのみ表示。
ユーザー2の詳細ページでキーワード検索をしたら、ユーザー2の該当するコンテンツのみ表示。
というようにユーザーの詳細ページで検索をしたら、そのユーザーが投稿したコンテンツだけを検索結果として表示する実装がしたいです。

現状

以下を参考にransackを用いて、検索機能の実装を行いました。
検索機能の実装
Gem、ransackで複数カラム+条件から検索する

トップページでの検索は期待通りの実装をすることができました。
「学年」を選び検索をしたら、該当する学年のコンテンツのみ表示できます。
「教科」「カテゴリー」も同様に検索できます。

該当のソースコード

routes

1Rails.application.routes.draw do 2 devise_for :users 3 root to: "contents#index" 4 resources :contents 5 resources :users, only: [:show, :edit, :update] 6end

controller

1#contents 2def index 3 @q = current_user.contents.ransack(params[:q]) 4 @contents = @q.result.order("created_at DESC").includes([:rich_text_question], :answers) 5end

views

1#contents/index 2<%= search_form_for @q do |f| %> 3 <div class="main-search"> 4 <div class="main-search-container"> 5 <div class="main-search-grade"> 6 <%= f.collection_select :grade_id_eq, Grade.where.not(id: 1), :id, :name, include_blank: "学 年" %> 7 </div> 8 <div class="main-search-subject"> 9 <%= f.collection_select :subject_id_eq, Subject.where.not(id: 1), :id, :name, include_blank: "教 科" %> 10 </div> 11 <div class="main-search-category"> 12 <%= f.search_field :category_cont, placeholder: "カテゴリーを入力", class: "search-textarea" %> 13 </div> 14 <label class="main-search-btn"> 15 <i class="fa fa-search fa-fw"></i> 16 <%= f.submit class: "hidden" %> 17 </label> 18 </div> 19 </div> 20 <% if @contents.present? %> 21 <div class="main-contents"> 22 <%= render partial: "content", collection: @contents %> 23 </div> 24 <% else %> 25 <div class="content-empty-message"> 26 一致するコンテンツがありません。 27 </div> 28 <% end %> 29<% end %>

ここまでがトップページの検索に関する記述です。
次に、ユーザー1がユーザー2の詳細ページに遷移しユーザー2のコンテンツだけを検索できるように以下のように実装しました。

controller

1#user 2def show 3 @user = User.find(params[:id]) 4 @q = @user.contents.ransack(params[:q]) 5 @contents = @q.result.order("created_at DESC").includes([:rich_text_question], :answers) 6end

views

1#user/show 2(省略) 3<%= search_form_for @q do |f| %> 4 <div class="main-search"> 5 <div class="main-search-container"> 6 <div class="main-search-grade"> 7 <%= f.collection_select :grade_id_eq, Grade.where.not(id: 1), :id, :name, include_blank: "学 年" %> 8 </div> 9 <div class="main-search-subject"> 10 <%= f.collection_select :subject_id_eq, Subject.where.not(id: 1), :id, :name, include_blank: "教 科" %> 11 </div> 12 <div class="main-search-category"> 13 <%= f.search_field :category_cont, placeholder: "カテゴリーを入力", class: "search-textarea" %> 14 </div> 15 <label class="main-search-btn"> 16 <i class="fa fa-search fa-fw"></i> 17 <%= f.submit class: "hidden" %> 18 </label> 19 </div> 20 </div> 21 <div class="user-show-contents"> 22 <%= render partial: "contents/content", collection: @contents %> 23 </div> 24<% end %>

###起きた問題
ユーザー1がユーザー2の詳細ページ内にある検索フォームを選択・入力し、検索ボタンを押すとユーザー1のコンテンツで該当するものが表示されます。
もう少し詳しくいうと、他のユーザーの詳細ページで「中1」「英語」と学年・教科を選択し、検索ボタンを押したら、そのユーザーのコンテンツではなく、current_userのコンテンツの「中1」「英語」に該当するコンテンツが表示されます。
これをそのページのユーザーのコンテンツを表示するために、以下を参考に色々試してみました。
ransackを利用した色々な検索フォーム作成方法まとめ

###試したこと1

views

1<%= f.collection_select :grade_id_in, Grade.where.not(id: 1), :id, :name, include_blank: "学 年" %>

###試したこと2

controller

1def show 2 @q = @user.contents.search(search_params) 3 @contents = @q.result.order("created_at DESC").includes([:rich_text_question], :answers) 4end 5 6(省略) 7 8def search_params 9 params.require(:q).permit(:grade_id_eq, :subject_id_eq, :category).merge(user_id: user.id) 10end

エラー

param is missing or the value is empty: q

###試したこと3

controller

1#user 2def show 3 @q = @user.contents.ransack(params[:q]) 4 @contents = @q.result.order("created_at DESC").includes([:rich_text_question], :answers) 5 binding.pry 6end

binding.pryを用いて、@contentsに含まれている値をターミナルで確認。

[1] pry(#<UsersController>)> @contents Content Load (0.7ms) SELECT `contents`.* FROM `contents` WHERE `contents`.`user_id` = 2 ORDER BY created_at DESC ↳ app/controllers/users_controller.rb:8:in `show' ActionText::RichText Load (0.5ms) SELECT `action_text_rich_texts`.* FROM `action_text_rich_texts` WHERE `action_text_rich_texts`.`record_type` = 'Content' AND `action_text_rich_texts`.`name` = 'question' AND `action_text_rich_texts`.`record_id` IN (5, 2, 1, 3) ↳ app/controllers/users_controller.rb:8:in `show' Answer Load (0.3ms) SELECT `answers`.* FROM `answers` WHERE `answers`.`content_id` IN (5, 2, 1, 3) ↳ app/controllers/users_controller.rb:8:in `show' => [#<Content:0x00007fd863a55210 id: 5, grade_id: 7, subject_id: 5, category: "生物", release_id: 1, user_id: 2, created_at: Wed, 10 Feb 2021 18:36:05 JST +09:00, updated_at: Wed, 10 Feb 2021 18:36:05 JST +09:00>, #<Content:0x00007fd863af66d8 id: 2, grade_id: 2, subject_id: 3, category: "連立方程式", release_id: 2, user_id: 2, created_at: Fri, 05 Feb 2021 20:30:41 JST +09:00, updated_at: Sun, 14 Feb 2021 15:04:37 JST +09:00>, #<Content:0x00007fd863af6520 id: 1, grade_id: 2, subject_id: 6, category: "現在進行形", release_id: 2, user_id: 2, created_at: Fri, 05 Feb 2021 15:12:41 JST +09:00, updated_at: Sun, 14 Feb 2021 15:04:37 JST +09:00>,

@contentsにはしっかりとユーザー2のコンテンツが格納されていることは確認できました。
しかし、その中のものを検索後どのように表示するかがわかりません。

長くなりましたが、以上になります。ご助言いただけると幸いです。

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

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

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

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

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

guest

回答2

0

自己解決

views

1#users/show 2<%= search_form_for @q, url: user_path do |f| %>

というようにusers/showのPrefixを確認し、urlを指定すれば解決しました。

投稿2021/02/24 08:28

shawn_709

総合スコア13

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

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

0

???
「検索できるように以下のように実装しました。」
のcodeと
「試したこと3」のcodeとどこが違います?
@user = User.find(params[:id]) を def show のなかでやるか外でやるかだけの違いに見えるのですが。。。。

「その中のものを検索後どのように表示するかがわかりません。」
これがまた???です。
起きた問題に「ユーザー1のコンテンツで該当するものが表示されます。」
とあります。
それと同じように行えば @contents には ユーザー2のコンテンツが入っているのですから、それが表示されるのでは?
うまくいかないようでしたらpartial: "contents/content"を載せてください。

気になるのは
view show に user id がない ⇒ 検索するとき、def show は どのユーザについてかがわからない

これがトラブルの元かも。
hidden_field で id として user_idを用意して検索時にparamsに入れる必要があるのでは?

投稿2021/02/14 12:19

winterboum

総合スコア23567

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問