Rails ネストした関連先のテーブルもまとめて保存する (accepts_nested_attributes_for、fields_for)

  • 43
    Like
  • 0
    Comment
More than 1 year has passed since last update.

ひとつのフォームの中で複数のフィールドの登録をまとめて行いたいことがあります。そんなときに便利な方法を紹介します。
has_many関連の子レコードをまとめて登録出来るようになります。
キーワードは「accepts_nested_attributes_for」と「fields_for」です。

入れ子のフォームを扱うための下準備

テーブルをまとめて登録するために入れ子のフォームを作成することになります。それを可能にするためにaccepts_nested_attributes_forというメソッドを使いましょう。

今回はteamsテーブルとmembersテーブルで話を進めたいと思います。
以下のような関係となります。

app/models/team.rb
class Team < ActiveRecord::Base
  has_many :members
end
app/models/members.rb
class Member < ActiveRecord::Base
  belongs_to :team
end

それではaccepts_nested_attributes_forの設定を行いますが、設定は簡単です。
以下のようにteam.rbに追記するだけです。

app/models/team.rb
class Team < ActiveRecord::Base
  has_many :members
  accepts_nested_attributes_for :members #この行を追加
end

実際にフォームを使って登録する

app/controller/teams_controlelr.rb
class TeamsController < ApplicationController
  def new
    @team = Team.new
    @team.members.build
  end
end

以下のように、fields_forを使ってフォームの中に入れ子を作ることが出来ます。

views/groups/new.html.haml
.row.form
  %p= '新規グループ作成'
  .col-lg-8
    = form_for @team do |f|
      = f.text_field :name, placeholder: 'グループ名を入力してください', cols: '30', rows: '10', autofocus: 'true', class: 'form-control'
      = f.text_area :description, placehoder: 'グループの説明を入力してください', autofocus: 'true', class: 'form-control'
      = f.file_field :logo
      = f.fields_for :members do |m|
        = m.text_field :nickname
        = m.file_field :avatar
      = f.submit '作成する', class: 'btn btn-primary'

以下のようにコントローラーを記述することで、まとめて2つのテーブルのレコードを追加出来ます。

app/controller/teams_controlelr.rb
class TeamsController < ApplicationController
  def create
    Team.create(team_params)
  end
end

private
def team_params
  params.require(:team).permit(:name, :description, :logo, members_attributes: [:nickname, :avator])
end

参考
Railsでaccepts_nested_attributes_forとfields_forを使ってhas_many関連の子レコードを作成/更新するフォームを作成