ネストしたモデルの入力フォーム実装
以下(Sorce:)のURLを参考にRails3のサンプルアプリを実装してみました。
まずはscaffoldでカテゴリとサブカテゴリを作成します。
$ rails g scaffold category name:string code:string available:boolean
$ rails g scaffold sub_category category_id:integer name:string code:string available:boolean
jQueryを使いたいので、Gemfileに一行追加して
gem 'jquery-rails'
jquery-railsのインストールとマイグレーションを実行します。
$ bundle install $ rails g install:jquery $ rake db:migrate
モデルの関連付け
app/models/category.rb
class Category < ActiveRecord::Base has_many :sub_categories, :class_name => "SubCategory", :dependent => :destroy accepts_nested_attributes_for :sub_categories, :allow_destroy => true end
app/models/sub_category.rb
class SubCategory < ActiveRecord::Base belongs_to :category, :class_name => "Category" end
ヘルパーとJSの実装
app/helpers/application_helper.rb
module ApplicationHelper def link_to_remove_fields(name, f) f.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)") end def link_to_add_fields(name, f, association) new_object = f.object.class.reflect_on_association(association).klass.new fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder| render("fields_" + association.to_s.singularize, :f => builder) end link_to_function(name, raw("add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")")) end end
子要素を追加、削除するリンクをそれぞれ追加しています。
※ 注1: link_to_add_fieldsメソッドのrenderする部分テンプレートの名前を変更しました。
※ 注2: link_to_functionの第二引数、h()→raw()に修正しました。(Rails3なので)
public/javascripts/application.js
// application_jquery.js function remove_fields(link) { $(link).prev("input[type=hidden]").val("1"); $(link).closest(".fields").hide(); } function add_fields(link, association, content) { var new_id = new Date().getTime(); var regexp = new RegExp("new_" + association, "g") $(link).parent().before(content.replace(regexp, new_id)); }
参考サイトの実装をそのままコピペ
ビューの実装
app/views/categories/_form.html.erb
<!-- ここから追加 --> <div class="field"> <%= f.fields_for :sub_categories, @sub_categories do |sub_category| %> <%= render 'fields_sub_category', {:f => sub_category} %> <% end %> <%= link_to_add_fields "新しくサブカテゴリを追加する", f, :sub_categories %> </div> <!-- ここまで --> <div class="actions"> <%= f.submit %> </div>
app/views/categories/_fields_sub_category.html.erb(sub_categories/_form.html.erbをコピーして修正)
<div class="fields"> <h2>サブカテゴリ</h2> <%= link_to_remove_fields "削除", f %> <div class="field"> <%= f.label :name %><br /> <%= f.text_field :name %> </div> <div class="field"> <%= f.label :code %><br /> <%= f.text_field :code %> </div> <div class="field"> <%= f.label :available %><br /> <%= f.check_box :available %> </div> </div>
※ 注1: div.fieldsは忘れずに指定してください。JSでエラーになってしまいます。
Source:
#196 Nested Model Form Part 1 - RailsCasts
#197 Nested Model Form Part 2 - RailsCasts