やりたいこと
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/2/edit
github
https://github.com/kasei-san/relation_form_sample