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

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

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

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

Q&A

解決済

1回答

3310閲覧

検索フォームで、動的に変わるセレクトボックスを使いたい

pecchan

総合スコア592

Ruby on Rails 5

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

0グッド

0クリップ

投稿2020/07/05 02:10

編集2020/07/06 04:04

rails 5.2で検索画面を作ってるところです。

検索条件の入力項目として、「カテゴリ」>「サブカテゴリ」と連動するセレクトボックスを追加したいです。

以下を参考にセレクトボックスを追加してみましたが、応用できずにいます・・・。
Ajaxでセレクトボックスの中身が動的に変わるRailsアプリの作り方

rails

1 2 <%= form_with url: items_path, method: :get, local: true do |f| %> 3 4 <% category_options = Category.order(:id).map { |c| [c.name, c.id, data: { children_path: category_sub_categories_path(c) }] } %> 5 <%= f.label :category_id %> <%= label_tag(:category, "", class: 'optional_field') %> 6 <%= select :search, :category_id, category_options, {include_blank: ""}, {class: 'select-parent'} %> 7 8 <% sub_categories = @item.category.try(:sub_categories) || [] %> 9 <% sub_category_options = sub_categories.map { |c| [c.name, c.id] } %> 10 <%= select :search, :sub_category_id, sub_category_options, {include_blank: ""}, {class: 'select-children'} %> 11 12 <%= f.submit "検索" , class: "btn btn-default" %> 13 <% end %> 14

1つ目のselectである「カテゴリ」は、表示され検索も出来ました。

問題は、2つ目のselectを作る部分です。
参考先では、下のように@itemを使っています。

ruby

1<% sub_categories = @item.category.try(:sub_categories) || [] %>

今回作りたいのは検索フォームなので、関連するオブジェクトは不要かと思います。
この部分をどう記述すれば良いのでしょうか?

ruby

1f.category. 23Item.category.

とすると、違うようで下のエラーになります。

ActionView::Template::Error (undefined method `category' for #<ActionView::Helpers::FormBuilder:0x00007f88584ff8e8>):

それともここは、検索フォームですがコントローラから、

ruby

1def index 2 @item = Item.new 3end

して
@itemを渡してあげるべきなのでしょうか?

初心者につき的外れの質問しているかもしれませんが、どうかアドバイス宜しくお願いします。


ご指摘により
以下から不足情報を追加


カテゴリモデル

ruby

1class Category < ApplicationRecord 2 has_many :sub_categories 3 has_many :items 4 default_scope -> { order(:order_number) } 5end 6

サブカテゴリモデル

ruby

1class SubCategory < ApplicationRecord 2 belongs_to :category 3 has_many :items 4 default_scope -> { order(:order_number) } 5end 6

アイテムモデル※検索したい対象

ruby

1class Item < ApplicationRecord 2 3 belongs_to :category 4 belongs_to :sub_category 5 6 7 scope :search, ->(search_params) do 8 return if search_params.blank? 9 10 keyword_like(search_params[:keyword]) 11 .category_id_is(search_params[:category_id]) 12 .sub_category_id_is(search_params[:sub_category_id]) 13 end 14 scope :keyword_like, -> (keyword) { where('description LIKE ? or title LIKE ?', "%#{keyword}%","%#{keyword}%") if keyword.present? } 15 scope :category_id_is, -> (category_id) { where(category_id: category_id) if category_id.present? } 16 scope :sub_category_id_is, -> (sub_category_id) { where(sub_category_id: sub_category_id) if sub_category_id.present? } 17 18 19 20end 21

不足情報を追加


コントローラ

ruby

1 2class SubCategoriesController < ApplicationController 3 def index 4 5 @sub_categories = SubCategory.where(category_id: params[:category_id]) 6 7 respond_to do |format| 8 format.html do 9 end 10 11 format.js do 12 render json: @sub_categories.select(:id, :name) 13 end 14 end 15 16 end 17end 18

coffeescript

coffeescript

1$(document).on 'turbolinks:load', -> 2 replaceSelectOptions = ($select, results) -> 3 $select.html $('<option>') 4 $.each results, -> 5 option = $('<option>').val(this.id).text(this.name) 6 $select.append(option) 7 8 replaceChildrenOptions = -> 9 childrenPath = $(@).find('option:selected').data().childrenPath 10 $selectChildren = $(@).closest('form').find('.select-children') 11 if childrenPath? 12 $.ajax 13 url: childrenPath 14 dataType: "json" 15 success: (results) -> 16 replaceSelectOptions($selectChildren, results) 17 error: (XMLHttpRequest, textStatus, errorThrown) -> 18 console.error("Error occurred in replaceChildrenOptions") 19 console.log("XMLHttpRequest: #{XMLHttpRequest.status}") 20 console.log("textStatus: #{textStatus}") 21 console.log("errorThrown: #{errorThrown}") 22 else 23 replaceSelectOptions($selectChildren, []) 24 25 $('.select-parent').on 26 'change': replaceChildrenOptions

分かった所までを追加


その後分かった所までを追記致します。

エラーログはブラウザ、サーバともに出てませんでした。

ただ、正常な流れは、
親(Category)のセレクトボックスを変更で
スクリプトのreplaceChildrenOptions = ->に飛ぶのに対し、
今回のこの画面は、
replaceChildrenOptions = ->に飛びません。
replaceChildrenOptions = ->の真下にalertで確認しました。

ここからまったく分かりません・・・。


htmlを追加


出力されてるhtmlを追記致します

html

1 2<select class="select-parent" name="search[category_id]" id="search_category_id"> 3 <option value=""></option> 4 <option data-children-path="/categories/1/sub_categories" value="1">野菜</option> 5 <option data-children-path="/categories/2/sub_categories" value="2">果物</option> 6 <option data-children-path="/categories/3/sub_categories" value="3">お肉</option> 7 <option data-children-path="/categories/4/sub_categories" value="4">魚介</option> 8</select> 9 10<select class="select-children" name="search[sub_category_id]" id="search_sub_category_id"> 11 <option value=""></option> 12 <option value="1">キャベツ</option> 13 <option value="2">人参</option> 14 <option value="3">玉ねぎ</option> 15 <option value="4">ブロッコリー</option> 16 <option value="5">もやし</option> 17 <option value="6">レタス</option> 18 <option value="7">トマト</option> 19</select> 20

以下は登録画面のhtmlです。
こちらでも同じセレクトボックス連動を使用しており、こちらは正常に動作済みです。

html

1 2<select class="select-parent" name="item[category_id]" id="item_category_id"> 3 <option value="">選択して下さい</option> 4 <option data-children-path="/categories/1/sub_categories" value="1">野菜</option> 5 <option data-children-path="/categories/2/sub_categories" value="2">果物</option> 6 <option data-children-path="/categories/3/sub_categories" value="3">お肉</option> 7 <option data-children-path="/categories/4/sub_categories" value="4">魚介</option> 8</select> 9 10<select class="select-children" name="item[sub_category_id]" id="item_sub_category_id"> 11 <option value="">選択して下さい</option> 12</select>

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

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

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

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

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

winterboum

2020/07/05 04:18

カテゴリーとサブカテゴリの関係がわかる様にしてください 同じモデルなのか違うモデルなのかもわからないし
pecchan

2020/07/05 04:20

記載不足すみません、失礼しました。 追記致します。
guest

回答1

0

ベストアンサー

erb

1sub_categories = @item.category.try(:sub_categories) || []

erb

1sub_categories = Category.first.sub_categories || []

にしてみたら、どうでしょうか。

投稿2020/07/05 07:37

Cojiro

総合スコア539

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

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

pecchan

2020/07/05 14:40

有難う御座います。 どのCategoryを選んでも同じ種類(先頭のCategoryに紐づく)のSubCategoryが表示されました。 具体的に言うと、カテゴリが、野菜、果物、魚介の場合、 どれを選んでもサブカテゴリは キャベツ、人参、玉ねぎが表示がされます。
Cojiro

2020/07/05 14:46 編集

その部分はJavaScriptと別のコントローラ のアクションで実装してください。 貼ってくれたリンクに書いてあるまさにこの部分です。 ---- ユーザーが親カテゴリが変更する JavaScriptのchangeイベントが呼ばれる JavaScriptがサーバーに子カテゴリの一覧を問い合わせる サーバーが子カテゴリの一覧をJSONで返す JavaScriptがサーバーから子カテゴリの一覧を受け取る 子カテゴリセレクトボックスの中身をサーバーから受け取った子カテゴリの一覧で置き換える ----
pecchan

2020/07/05 21:25

度々すみません、有難う御座います。 JavaScriptと別のコントローラは、記載漏れでした。すみません。 一応実装はしておりました。
Cojiro

2020/07/05 22:23

そうだったんですね。 では、親カテゴリのセレクトボックスを変更したときに、ブラウザのコンソールやサーバーのログにエラーなどは出力されていますか?
pecchan

2020/07/06 00:00

有難う御座います。 確認したところ、セレクトボックスのチェンジイベントでログが一切出てませんでした。 まだ特定してませんが、イベントが走っていないのが原因かもしれません。
Cojiro

2020/07/06 00:09

なるほど。 それでは、 やはり下記の内容が要点をまとめられているので、 これに基づいてどこまでできていて何ができていないのかをまずは把握するのが良さそうですね。 ブラウザ(JS)であれば、console.log、サーバーであればputsやloggerを使えばログを出力できるので、これらを利用しながら進めてみてください。 ---- ユーザーが親カテゴリが変更する JavaScriptのchangeイベントが呼ばれる JavaScriptがサーバーに子カテゴリの一覧を問い合わせる サーバーが子カテゴリの一覧をJSONで返す JavaScriptがサーバーから子カテゴリの一覧を受け取る 子カテゴリセレクトボックスの中身をサーバーから受け取った子カテゴリの一覧で置き換える ----
pecchan

2020/07/06 00:44 編集

度々有難う御座います。 これは今回関係ないと思って記載してなかったのですが、検索画面は、モーダルウィンドウで実装してます。 ※一覧画面上から詳細検索ボタンを押すと表示 つまりスクリプト読み込み時に、select boxは存在してない状態です。 これが原因でしょうか? モーダルウィンドウ表示時に、モーダルウィンドウ?view?からスクリプトを再読み込みする方法はないでしょうか? 探していますが見つかりません。 それとも検討違いでしょうか?
pecchan

2020/07/06 00:52

失礼しました。 choromeなのですが、「検証」で見たら、モーダルダイアログ表示前からselect box存在してました。
pecchan

2020/07/06 03:39

親カテゴリのチェンジ時に、 replaceChildrenOptions = ->が呼ばれていないの原因でした。 replaceChildrenOptions = -> の真下にalertでデバッグして確認しました。 なぜ呼ばれないのか、までは分かりませんでした(泣)
pecchan

2020/07/06 05:05

有難う御座います。 よく読んでみます。
pecchan

2020/07/07 03:31 編集

お世話になってます。 参考先は構文ミスが原因のようで、今回のこちらとは関係なさそうでした。 未だに検証中ですが、 モーダルウインドウ側に置いてた検索フォームを、index側に移動させると、changeイベントが正常に動作しました。 なので、やはりモーダルウィンドウが原因のように思います。 次に、モーダルウインドウ側で動的に生成していたselect boxをタグ直書きで置いてイベント発火するかだけを試すと、これはなぜか発火しませんでした。ここでお手上げ状態です(泣) モーダルウインドウ上に「class = select-parent」というオブジェクトはあるのに操作できません。 エラーは出てません。 モーダルウインドウの特性がいまいち分からないのですが、 スクリプト側からモーダルウインドウは認識出来ないのでしょうか?
pecchan

2020/07/07 04:25

元々ご提示いただいた、 sub_categories = Category.first.sub_categories || [] で紐づくデータは表示できてますので解決とさせていただきます。 モーダルウインドウになると駄目な件は、未解決ですが新たに質問を立てさせていただこうと思います。 この度はお付き合いいただき有難う御座いました。
Cojiro

2020/07/07 06:42

そうでしたか。 参考までに、、、 スクリプトがDOMの読み込みができるのは、HTMLに表現されているもののみです。 pecchanさんのおっしゃってることが、正しいとすれば、 チェンジイベントを登録しているタイミングでは、まだモーダルのDOMができていないかもしれません。 デバッグして確かめてみるといいと思います。 CSSフレームワークを利用しているのであれば、フレームワーク側にそういった場合の回避方法がある可能性があるので、確認してみるといいかもしれません。
pecchan

2020/07/07 07:22

有難う御座います。 「検証」で確認できたので、DOM生成済みと認識してました。 CSSフレームワークはbootstrapを使用してます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問