cocoon を使って、1フォームで1対多のモデルを動的に編集できるようにする

やりたいこと

Railsで1対多のmodelがあるときに、 親modelのformで子modelを動的に追加したり削除したりしたい

方法

nathanvda/cocoon を使う

つくりかた

Gemfile

gem 'cocoon'

Item の scaffold を generate

rails g scaffold item name:string price:integer

Photo model を generate

rails g model photo title:string item_id:integer

Item と、Photo をリレーション

app/models/Photo.rb

class Photo < ActiveRecord::Base
  belongs_to :item
end

app/models/item.rb

class Item < ActiveRecord::Base
  has_many :photos, dependent: :destroy
end

db/seeds.rb

1.upto(10) do |i|
  item = Item.create(name: "item_#{i}", price: i*100)
  1.upto(5) do |j|
    item.photos << Photo.create(title: "#{i}_#{j}")
  end
end

ここで急に haml で書きたくなった

Gemfile

gem 'haml-rails'
gem 'erb2haml'
bundle install

一括変換!

rake haml:replace_erbs

ItemController#show で、 Photo を表示するように

app/controllers/items_controller.rb

    def set_item
      @item = Item.includes(:photos).find(params[:id])
    end

app/views/items/show.html.haml

%p
  %strong Name:
  = @item.name
%p
  %strong Price:
  = @item.price
%ul
  - @item.photos.each do |photo|
    %li
      = photo.title

Item の form で Photo を更新可能に

動的な追加/削除のための js ライブラリを追加

app/assets/javascripts/application.js

//= require cocoon

cocoonが使うパラメータを許可(_destroy は削除用)

app/controllers/items_controller.rb

     def item_params
       params.require(:item).permit(:name, :price, photos_attributes: %i[id title _destroy])
     end

子要素の追加/編集/削除を許可

app/models/item.rb

accepts_nested_attributes_for :photos, reject_if: :all_blank, allow_destroy: true

子要素を編集するフォームを追加

app/views/items/_form.html.haml

 %h3 Photos
 #photos
   = f.fields_for :photos do |photo|
     = render 'photo_fields', f: photo
   .links
     = link_to_add_association 'add photo', f, :photos```

app/views/items/_photo_fields.haml

.nested-fields
  .field
    = f.label :title
    %br
    = f.text_field :title
  = link_to_remove_association 'remove', f

できた!

http://localhost:3000/items

f:id:kasei_san:20160324222259p:plain

http://localhost:3000/items/2

f:id:kasei_san:20160324222330p:plain

http://localhost:3000/items/2/edit

f:id:kasei_san:20160324222358p:plain

github

https://github.com/kasei-san/relation_form_sample

参考