前提
親(Project)-子(task)-孫(item) 関係
子を消すと孫も消える
環境
rails 5.1.5
# Cocoonのインストール
gem入れてjavascript.rbにcocoonの呼び出し文追加
(ここあとで加筆)
## 設定
model
class Project < ApplicationRecord
has_many :tasks, inverse_of: :project
accepts_nested_attributes_for :tasks, reject_if: :all_blank, allow_destroy: true
end
class Task < ApplicationRecord
belongs_to :project
has_many :items, inverse_of: :task
accepts_nested_attributes_for :items, reject_if: :all_blank, allow_destroy: true
end
class Item < ApplicationRecord
belongs_to :task
end
- allow_destroy: true としていないと子項目の削除ができない
controller
def new
@project = Project.new
@task = @project.tasks.build
@item = @task.items.build
end
:
private
def project_params
params.require(:project).permit(:name, :description, tasks_attributes: [:id, :description, :done, :_destroy,
items_attributes: [:id, :description, :_destroy]])
end
- 合わせてストロングパラメーターの _destroy も入れておく必要がある(入れないと削除できない)
- 子要素は親要素のストロングパラメーターに含めて記述できる
- インスタンスは最初に表示した時のフォームに対応するので、子用のフォームが最初になくても良ければ
@project = Project.new
だけでよさそう
View
<h1>New Project</h1>
<%= render 'form', project: @project %>
<%= link_to 'Back', projects_path %>
<%= form_for @project do |f| %>
<div class="field">
<%= f.label :name, "name" %>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :description, "description" %>
<%= f.text_field :description %>
</div>
<h3>Tasks</h3>
<div id="tasks">
<%= f.fields_for :tasks do |task| %>
<%= render 'task_fields', f: task %>
<% end %>
<div id="links">
<%= link_to_add_association 'add task',f, :tasks %>
</div>
<%= f.submit %>
</div>
<% end %>
<div class="nested-fields well well-compact">
<div class="form-group">
<%= f.label :description %>
<%= f.number_field :description %><br>
<%= link_to_remove_association "remove task", f %>
</div>
<div class="items">
<%= f.fields_for :items do |item| %>
<%= render 'item_fields', f: item %>
<%end%>
<div class="links">
<%= link_to_add_association "add item", f, :items %>
</div>
</div>
</div>
<div class="nested-fields form-inline">
<div class="form-group">
<%= f.label :itemdescription %>
<%= f.number_field :description %>
</div>
</div>
- _{model}_fields.html.erbというパーシャル名が固定(拡張子はいくつかフォローされてるので要公式確認)
- 上記パーシャルへnested-fieldsというclassを設定する
- =link_to_add_attributesの前にlinksというclassを設定する
ハマリポイント:
rails5からはjQueryのサポートがないので、gemのインストールが必要
gem "jquery-rails"
以下の追記も必要
//= require jquery
それでも動かない場合、Appication.jsへの”述の順番見るといいかも
//= require jquery ←
//= require rails-ujs
//= require turbolinks
//= require_tree .
//= require cocoon ←
cocoonはjqueryを前提にしているので、先に記述がないとだめみたい
エラーになった順番大事…
感想
-
公式が上げてるデモサンプルコード見て実装するのいいかも…!(その通りにやったらできた)https://github.com/nathanvda/cocoon_simple_form_demo
-
フォームパーシャルで切ってると、editとnewを全然いじらなくていいのでめっちゃ楽
-
サンプルコードがhtm.erbじゃなくてhamlという書式?を使っていたので読解に手間取った
#### 参考
cocoonをRails5.1で使用しようと思った時にハマる罠
http://toyokappa.hatenablog.com/entry/2017/09/15/001537
【jQuery】プログラム動かない時に確認すること
http://mikaduki.info/webprogram/js/jquery/1192/
cocoon を使って、ネストしたフォームを作る
http://mikazuki.hatenablog.jp/entry/2016/03/26/040229
マークアッパー的 Haml入門21の手引き
http://fukuyama.co/haml2
Hamlでクラスを複数指定する。
https://qiita.com/s_osa/items/82afd6e543fe4298a2d8