LoginSignup
34

More than 5 years have passed since last update.

Cocoonで親子(孫)関係で、動的にフォームを追加削除する

Last updated at Posted at 2018-02-26

前提

親(Project)-子(task)-孫(item) 関係
子を消すと孫も消える

環境

rails 5.1.5

 Cocoonのインストール

gem入れてjavascript.rbにcocoonの呼び出し文追加
(ここあとで加筆)

 設定

model

project.rb
class Project < ApplicationRecord
  has_many :tasks, inverse_of: :project
  accepts_nested_attributes_for :tasks, reject_if: :all_blank, allow_destroy: true
end
task.rb
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
item.rb
class Item < ApplicationRecord
  belongs_to :task
end
  • allow_destroy: true としていないと子項目の削除ができない

controller

projects_controller.rb
  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

new.html.erb
<h1>New Project</h1>
<%= render 'form', project: @project %>
<%= link_to 'Back', projects_path %>
_form.html.erb
<%= 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 %>
_task_fields.html.erb
<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>

_item_fields.html.erb
<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"

以下の追記も必要

application.js
//= 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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34