コンボボックスで都道府県を選んだ後に、選んだ都道府県下の市町村を絞りこんで表示させたい。
Rails3になって、observe_fieldというフィールドの更新を検知する関数がなくなったり、Ajax周りの関数が変更になっていたりで、そのまま利用できるサンプルは少なかった。
最も参考になったのは、下記のブログ記事。
[Rails3]jQueryでobserve_field的なことを。
まずは、都道府県と市町村、その他住所クラスのscaffoldを作成する。(実行結果は省略。)
rails g scaffold todofuken name:string rails g scaffold shichoson todofuken:references name:string rails g scaffold jusho todofuken:references shichoson:references sonotajusho:stringscaffoldで作成された_form.html.erbは、TodofukenとShichosonがテキストフィールドになっているので、下記のようにコンボボックスに変更する。
<%= form_for(@jusho) do |f| %> <% if @jusho.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@jusho.errors.count, "error") %> prohibited this jusho from being saved:</h2> <ul> <% @jusho.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= f.label :todofuken %><br /> <%= f.collection_select(:todofuken_id, Todofuken.find(:all), :id, :name) %> </div> <div class="field"> <%= f.label :shichoson %><br /> <%= f.collection_select(:shichoson_id, Shichoson.find(:all), :id, :name) %> </div> <div class="field"> <%= f.label :sonotajusho %><br /> <%= f.text_field :sonotajusho %> </div> <div class="actions"> <%= f.submit %> </div> <% end %>
次に、市町村の部分のhtmlをAjaxで変更できるように外出しにする。
_todoufuken_select.html.erb
<%= f.select(:shichoson_id, @shichoson) %>_form.html.erbからは、下記のようにrenderで呼び出す。
<%= render 'todoufuken_select', {:f => f} %>{:f => f}と指定しておくと、_form.html.erbのFormの変数(:shichoson)が、_todoufuken_select.html.erb内でも使えるようになる。
次に、都道府県のコンボボックスの変更を検知するために、JavaScriptを記述する。
application.js
jQuery(function(){ $('#jusho_todofuken_id').change(function(){ var todofuken_id = $("#jusho_todofuken_id").val(); $.get("todoufuken_select.js?todofuken_id=" + todofuken_id); });todoufuken_select.js の部分は、URLとしては/jushos/todoufuken_select.js になる。
scaffoldを実行した直後だと、/jushos/XXXX のリクエストは、すべてコントローラーのshowメソッドで処理されてしまうので、ルーティングを下記のように追加する。
routes.rb
Mytest::Application.routes.draw do match '/jushos/todoufuken_select' resources :jushosmatch~の部分をresources :jushosの先に記述する必要がある。 ※showメソッドの/jushos/XXXXのルーティングの方が範囲が広いので、先にヒットしてしまう。
次に、コントローラーを修正する。
jushos_controller.rb
# GET /jushos/new # GET /jushos/new.json def new @jusho = Jusho.new @shichoson = [["都道府県を選択してください。", "0"]] respond_to do |format| format.html # new.html.erb format.json { render json: @jusho } end end
# GET /jushos/todoufuken_select def todoufuken_select @shichoson = Shichoson.find_all_by_todofuken_id(params[:todofuken_id]) render end変更点は2箇所。
既存のnewメソッドに、市町村のコンボボックスの初期値を設定したことと、todoufuken_selectメソッドの新規追加。
次に、todoufuken_selectメソッドが呼び出すことになる_todoufuken_select.html.erbを作成する。
$("#jusho_shichoson_id").html("<%= escape_javascript(options_for_select(@shichoson.map{ |shichoson| [shichoson.name, shichoson.id] })) %>");options_for_selectは、selectタグのoprionの部分を作成する関数だが、ここにDBの検索結果の配列(@shichoson)をそのまま渡してもうまく表示されないので、上記のように、DBの列を指定して渡すようにする。
これで完成。
初期状態
都道府県で愛知県を選択
愛知県の市町村が表示された。
こんにちは。すばらしい投稿、誠にありがとうございます。
返信削除rails g scaffold todofuken name:string
rails g scaffold shichoson todofuken:references name:string
rails g scaffold jusho todofuken:references shichoson:references sonotajusho:string
を実行しましたところ、サンプルでご提示いただいている内容とかなり異なるようでした。
異なる部分だけを、サンプルと同じように記載すればよろしいものでしょうか?
また、「shichosons」「todofukens」の両方に、”_form.html.erb”が生成され
ておりますが、両方、サンプルと同じ内容で修正すればよろしいものでしょうか?