- よく使うのでメモ書きに、最終的にこんな感じになります。
- 完成後のリポジトリはこちら
インストール
-
nested_attributes
のフォームを作る時にcocoonというGemを使うと便利なので、それを使います。
gem 'cocoon'
- cocoonを使うためには、Gemのインストールと、
assets/application.js
への登録が必要です。
//= require cocoon
- あとBootstrap4をRailsで使うので、あらかじめ設定しておいてください。(こちらの記事にわかりやすくまとめてありました。@NaokiIshimuraさんありがとうございます。)
モデルへの実装
- 今回はわかりやすく
User
とDog
を一対多で関連づけます。(nested_attributes
を忘れない。) - またコードの簡略化のため、それぞれのモデルのパラメーターを配列にして定数化しておきます。
class User < ApplicationRecord
ATTRIBUTES = %i[name].freeze
has_many :dogs, dependent: :destroy, inverse_of: :user
accepts_nested_attributes_for :dogs, allow_destroy: true, reject_if: :all_blank
end
class Dog < ApplicationRecord
# nested_attributesの都合上、idと_destroyを加えている。
ATTRIBUTES = %i[id _destroy name].freeze
belongs_to :user
end
コントローラーへの実装
-
nested_attributes
のStrongParameterの対応を忘れない。
class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
redirect_to @user
else
render :new
end
end
private
def user_params
params
.require(:user)
.permit([*User::ATTRIBUTES, dogs_attributes: Dog::ATTRIBUTES])
end
end
ビューの実装
- ビューの構成は以下の通りです。(今回使う箇所だけ)
- cocoonの仕様で、子要素のテンプレートになる
_〇〇_fields.html.slim
を作らないといけないことに注意してください。 - cocoonのビュー周りの注意点は公式のリポジトリにまとめてあるので、気になった方は確認してください。
app/views/users/
├── _dog_fields.html.slim
├── new.html.slim
└── show.html.slim
- 実際のコードは以下。
/ show.html.slim
p
strong Name:
= @user.name
ul
- @user.dogs.each do |dog|
li = dog.name
=> link_to 'Edit', edit_user_path(@user)
'|
=< link_to 'Back', users_path
/ new.html.slim
h2.py-3 New use
= form_for @user do |f|
.form-group.row
.col-md-3
= f.label :name
.col-md-9
= f.text_field :name, class: 'form-control'
.form-group.row
.col-md-3
= f.label :dogs
.col-md-9.ml-auto
#dogList
= f.fields_for :dogs do |dog|
= render 'dog_fields', f: dog
= link_to_add_association f, :dogs, class: "btn btn-link", data: { association_insertion_node: "#dogList", association_insertion_method: "append" } do
= fa_icon "plus", text: "アイテムを追加"
= f.submit 'Submit', class: 'btn btn-success w-100'
/ _dog_fields.html.slim
.nested-fields.mb-3
.form-row
.col-md-10
= f.text_field :name, placeholder: '名前', class: 'form-control'
.col-md-2
= link_to_remove_association "削除", f, class: "btn btn-danger"
- cocoonの仕様上、nested-fieldsクラスを子要素につけないと追加されません。
- これにより、「追加ボタン」の位置を一番下にしたまま、新しいフォームが追加されます。
まとめ
- こんな感じで作ればすんなりと
nested_attributes
のフォーム実装ができるかと思います!