一つのフォームから複数のmodelにデータを送りたい場合に使用するのが、form_for / fields_forです。ただし、その複数存在するmodel間の関係性によって微妙に使い方が違うのをご存知ですか??今回は、その違いをまとめてみました。
親と子の要素を一度に作成したい場合
userとそのuserの書いたbook(つまり、user_idを持つbook)をまとめて作成したい場合
- model
user.rb
has_many :books:
accepts_nested_attributes_for :books:
book.rb
belongs_to :user
- controller
users_controller.rb
class UsersContoller < AppricationController
def new
@user = User.new
@user.books.build
# controllerのポイント
# @user.books.build ←これで一括保存の準備は完了
end
def create
user = User.new(user_params)
user.save
# 親要素を保存かけてあげることで自動で子要素も保存されます!
end
private
def user_params
params.require(:user).permit(:name, books_attributes: [:title, published_at])
# これは独特な書き方ですが、このように子要素のstrong parameterを書くことで、自動で子要素に親要素のidもふられます。この場合だと、bookテーブルにあるuser_idにもきちんとこの時作成される親要素のidがふられます。
end
end
- view
users/new.html.erb
<%= form_for :user do |f| %>
<%= f.text_field :name %>
<%= f.fields_for :books do |b| %>
<%= b.text_field :title %>
<%= b.text_field :published_at %>
<%= f.submit %>
<% end %>
model間の関係は親子関係など特に無いが、一つのフォームから複数のmodelにむけてデータを送りたい場合
userテーブルとcorporationテーブルに一つのフォームからデータを送りたい場合
- controller
users_controller.rb
class UsersController < ApplicationController
def new
@user = User.new
@corporation = Corporation.new
# それぞれ.newをする
end
def create
user = User.new(user_params)
user.save
corporation = Corporation.new(corporation_params)
corporation.save
# それぞれcreate処理を行う
end
private
def user_params
params.require(:user).permit(:name)
end
def corporation_params
params.require(:corporation).permit(:name)
end
end
users/new.html.erb
<%= form_for @user, url: new_user_params do |f| %>
<%= f.text_field :name %>
<%= fields_for @corporation, new_corporation_params do |c| %>
<%= c.text_field :name %>
<%= f.submit %>
<% end %>
このようにして、model間の関係がないものも一つのフォームから送ることができます。
ちなみに、この場合パラメーターは以下のようになるので、それぞれstrog parameterでpermitしてあげてcreateすれば保存完了です。
{ "user" => { "name" => "userテスト"}, "corporation" => { "name" => "corporationテスト"}