FreeCamp      

【Rails】Gem cocoonを用いて親子関係の構築

一つのフォームで親子関係のある複数モデルのレコード作成かつ子モデルのレコードを複数挿入したい場合にgemのcocoonを使うと簡単に実装できます。
今回はタイトルしか挿入しない投稿フォームに子モデルのタグを複数挿入する機能を実装します。
(タイトルカラムのあるPostモデルとタグカラムのあるTagモデルは1対Nの関連であることが前提とします。)

目次

  1. シンプルな投稿フォームの作成
  2. Gem cocoonの導入
  3. タグのフォームを追加
    1. Tagモデルの作成
    2. PostモデルとTagモデルの関連付け
    3. タグの投稿フォームの作成
  4. 完成ソースコード

1. シンプルな投稿フォームの作成

まずは以下サイトを参考にしてシンプルな投稿フォームを作成していきます。

投稿フォームは作成できました。
続けてGem cocoonを導入していきます。

...追加
gem 'cocoon'
gem 'jquery-rails'
$ bundle
...編集
//= require rails-ujs
//= require activestorage
//= require jquery
//= require cocoon
//= require turbolinks
//= require_tree .

ここまででGem cocoonの準備ができました。
続いてTagのフォームも作成していきます。

3. タグのフォームを追加

3.1 Tagモデルの作成

Tagモデルのカラムはnameカラムとpost_idカラムを作成します。

$ rails g model Tag name:string post_id:integer
$ rails db:migrate

3.2 PostモデルとTagモデルの関連付け

PostモデルとTagモデルの関連付けを行います。
Postモデルが1に対し、TagモデルはNとします。
また、Postモデルのレコード作成時にTagモデルのレコードも同時に行いたいので、’accepts_nested_attributes_for’も使用します。

class Post < ApplicationRecord
  has_many :tags
  accepts_nested_attributes_for :tags, allow_destroy: true
end
class Tag < ApplicationRecord
  belongs_to :post
end

これで関連付けは完了です。

3.3 タグのフォームの作成

ネストしたフォームを作成するためにposts_controller.rbのnewアクションと_form.html.erbを編集します。

...編集
def new
  @post = Post.new
  @post.tags.build
end

...編集
def post_params
  params.require(:post).permit(:title, :content, tags_attributes: [:id, :name, :_destroy])
end
...(追加)
<%= form.fields_for :tags do |f| %>
  <%= f.label :name %>
  <%= f.text_field :name %>
<% end %>

ここまでの記述でPostモデルとその子モデルのTagモデルのレコードの挿入を一つのフォームでできるはずです。

次に一つの親モデルに対し複数の子モデルのレコードを挿入できるように編集していきます。

...編集
<div class="tags">
  <%= form.fields_for :tags do |f| %>
    <%= f.label "タグ" %>
    <%= render "tag_fields", f: f %>
  <% end %>
  <div class="links">
    <%= link_to_add_association "タグを追加", form, :tags %>
  </div>
</div>

タグのフォームを部分テンプレートにするためファイルを作成します

<div class="nested-fields">
  <%= f.text_field :name %>
  <%= link_to_remove_association "remove task", f %>
</div>

cocoonを使うと簡単にネストしたフォームを作成できます。
便利ですが正しい記述をしないと投稿や要素の追加や削除ができない場合があります。
要素(DOM)の操作はjqueryが便利です。
cocoonを使わずjqueryで実装するのも良いと思います。

4. 完成ソースコード

https://github.com/ssshhhooota/rails_cocoon