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

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

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

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

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

Q&A

解決済

2回答

4951閲覧

【Rails】Ajaxでセレクトボックスの中身が動的に変わる実装(3段構成)

taremimi_7

総合スコア20

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

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

0グッド

0クリップ

投稿2017/12/18 22:05

編集2017/12/18 22:15

#やりたいこと
親のカテゴリを変更すると、子のカテゴリの中身が動的に変わり、子のカテゴリが選択されると、孫のカテゴリも動的に変わるセレクトボックスをつくりたいです。
以下を参考にしました。
Ajaxでセレクトボックスの中身が動的に変わるRailsアプリの作り方(Qiita)
具体的にはUserが
Prefecture(都道府県)→School(学校)→Course(学科)
のカテゴリを動的に選択できるようにしたいです。
今のところPrefecture(都道府県)→School(学校)の2段目までは動いています。

##コード
View

ruby

1users/school.html.erb 2 3<% prefecture_options = Prefecture.order(:id).map { |s| [s.name, s.id, data: { children_path: prefecture_schools_path(s) }] }%> 4 <div class="field"> 5 <%= f.label :prefecture_id,"都道府県" %><br> 6 <%= f.select :prefecture_id, prefecture_options, { include_blank: true }, class: 'select-parent' %> 7 <span class="pulldown"><i class="fa fa-angle-down" aria-hidden="true"></i></span> 8 </div> 9 10 <% schools = @user.prefecture.try(:schools) || [] %> 11 <% school_options = schools.map { |s| [s.name,s.id , data: { grandchildren_path: prefecture_school_courses_path(s) }] } %> 12 <div class="field"> 13 <%= f.label :school_id,"大学名" %><br> 14 <%= f.select :school_id, school_options, { include_blank: true }, class: 'select-children' %> 15 <span class="pulldown"><i class="fa fa-angle-down" aria-hidden="true"></i></span> 16 </div> 17 18 <% courses = @user.school.try(:courses) || [] %> 19 <% course_options = courses.map { |s| [s.name, s.id] } %> 20 21 <div class="field"> 22 <%= f.label :course_id,"学科名" %><br> 23 <%= f.select :course_id, course_options, { include_blank: true }, class: 'select-grandchildren' %> 24 <span class="pulldown"><i class="fa fa-angle-down" aria-hidden="true"></i></span> 25 </div>

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#都道府県から大学名 9 replaceChildrenOptions = -> 10 childrenPath = $(@).find('option:selected').data().childrenPath 11 $selectChildren = $(@).closest('form').find('.select-children') 12 if childrenPath? 13 $.ajax 14 url: childrenPath 15 dataType: "json" 16 success: (results) -> 17 replaceSelectOptions($selectChildren, results) 18 error: (XMLHttpRequest, textStatus, errorThrown) -> 19 console.error("Error occurred in replaceChildrenOptions") 20 console.log("XMLHttpRequest: #{XMLHttpRequest.status}") 21 console.log("textStatus: #{textStatus}") 22 console.log("errorThrown: #{errorThrown}") 23 else 24 replaceSelectOptions($selectChildren, []) 25 26#大学名から学科名 27 replaceGrandChildrenOptions = -> 28 grandchildrenPath = $(@).find('option:selected').data().grandchildrenPath 29 $selectGrandChildren = $(@).closest('form').find('.select-grandchildren') 30 console.log($(@).find('option:selected').data().grandchildrenPath) 31 32 if grandchildrenPath? 33 $.ajax 34 url: grandchildrenPath 35 dataType: "json" 36 success: (results) -> 37 replaceSelectOptions($selectGrandChildren, results) 38 error: (XMLHttpRequest, textStatus, errorThrown) -> 39 console.error("Error occurred in replaceChildrenOptions") 40 console.log("XMLHttpRequest: #{XMLHttpRequest.status}") 41 console.log("textStatus: #{textStatus}") 42 console.log("errorThrown: #{errorThrown}") 43 else 44 replaceSelectOptions($selectGrandChildren, []) 45 46 $('.select-parent').on 47 'change': replaceChildrenOptions 48 49 $('.select-children').on 50 'change': replaceGrandChildrenOptions

Controller

ruby

1class SchoolsController < ApplicationController 2 def index 3 prefecture = Prefecture.find(params[:prefecture_id]) 4 render json: prefecture.schools.select(:id, :name) 5 end 6end

ruby

1class CoursesController < ApplicationController 2 def index 3 school = School.find(params[:school_id]) 4 render json: school.courses.select(:id, :name) 5 end 6end

Model

ruby

1class User < ApplicationRecord 2 belongs_to :prefecture, optional: true 3 belongs_to :school, optional: true 4 belongs_to :course, optional: true 5end

ruby

1class Prefecture < ApplicationRecord 2 has_many :schools, ->{ order(:id) } 3end

ruby

1class School < ApplicationRecord 2 belongs_to :prefecture, optional: true 3 has_many :courses, ->{ order(:id) } 4end

ruby

1class Course < ApplicationRecord 2 belongs_to :school, optional: true 3end

Routing

ruby

1Rails.application.routes.draw do 2 resources :users do 3 collection do 4 get '/:id/school' => 'users#school', as: "school" 5 end 6 end 7 resources :prefectures, only: [] do 8 resources :schools, only: :index do 9 resources :courses, only: :index 10 end 11 end 12end

##困ってるところ
子カテゴリ(学校)の決定後、
coffeescript内のconsole.log($(this).find('option:selected').data().grandchildrenPath);
がundefinedとなり、孫のカテゴリ(学科)が変化しない。

お詳しい方、ぜひともご教授ください。
よろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

ERBの中で<% school_options = schools.map { |s| [s.name,s.id , data: { grandchildren_path: prefecture_school_courses_path(s) }] } %>のようにしてdata属性を追加していますが、これはあくまでサーバーサイドで生成されるoptionです。

都道府県のオプションが変更されるとJS内で動的に学校のoptionが作成されます。このときにはdata属性が付かないので、grandchildrenPathの情報も当然取得できなくなってしまいます。

というわけで、以下のような対応方針を取るのはどうでしょうか。

  • 学校のJSONを返すときにgrandchildrenPathに相当する情報も一緒に返す
  • JS内で動的にoptionを作成する際に、data属性も一緒に付与する

ruby

1class SchoolsController < ApplicationController 2 def index 3 prefecture = Prefecture.find(params[:prefecture_id]) 4 schools = prefecture.schools.map do |school| 5 { 6 id: school.id, 7 name: school.name, 8 # pathの情報も付与する 9 path: prefecture_school_courses_path(school) 10 } 11 end 12 render json: schools 13 end 14end

CoffeeScript

1 replaceSelectOptions = ($select, results) -> 2 $select.html $('<option>') 3 $.each results, -> 4 option = $('<option>').val(this.id).text(this.name) 5 # サーバーから返ってきたpath情報をdata属性として付与(pathが返ってきた場合のみ) 6 if this.path 7 option.data('path', this.path) 8 $select.append(option)

なお、replaceSelectOptionsは再利用可能なメソッドになっているため、grandchildrenPathのような具体的なdata属性ではなく汎用的なpathという名前にしてあります。

なので、それに合わせてERBのgrandchildren_pathgrandchildrenPathpathに統一しておきましょう。

diff

1-<% school_options = schools.map { |s| [s.name,s.id , data: { grandchildren_path: prefecture_school_courses_path(s) }] } %> 2+<% school_options = schools.map { |s| [s.name,s.id , data: { path: prefecture_school_courses_path(s) }] } %>

diff

1 replaceGrandChildrenOptions = -> 2- grandchildrenPath = $(@).find('option:selected').data().grandchildrenPath 3+ grandchildrenPath = $(@).find('option:selected').data().path

投稿2017/12/24 07:18

jnchito

総合スコア357

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

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

taremimi_7

2017/12/24 21:38 編集

できましたああああああ!!!!本当に良かった、、、、お忙しい中本当にありがとうございました!???? とても助かりました!改めて本当にありがとうございました!????????????
guest

0

$(@).find('option:selected')は、都道府県のoptionと大学のoptionをどちらも取得してしまうため、grandchildrenPathがエラーになってしまうのでは?
フォームを増やしたのですから、idなどを追加してそれぞれ絞り込む必要があると思います。

投稿2017/12/19 05:59

namenamenameko

総合スコア234

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

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

taremimi_7

2017/12/20 01:56 編集

nameko_moto様 ご回答ありがとうございます! 教えて頂いた通り、 childrenPath = $(@).find('.select-parent option:selected').data().childrenPath grandchildrenPath = $(@).find('.select-children option:selected').data().grandchildrenPath としてみましたが、1個目も動かなくなってしまいました。 (もしやり方間違ってたら教えて下さい。。。。)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問