Edited at

【Rails】1つのform_forで複数モデルへデータ登録をする方法


概要

アソシエーションで紐付いている複数のモデルへのデータ登録に苦労したのでまとめておきます。

一つのform_forで複数のモデルへのデータ登録を可能にする方法です。

例)ユーザーモデルとアドレスモデルがある時に、1つのform_forでユーザーモデルとアドレスモデルに同時にデータを渡したい。


環境

Rails5.1

mysql


前提

ユーザー情報の登録を実施。

Usersテーブル

・id

・name

Addressesテーブル

・都道府県

・市区町村

・番地


ポイント

accepts_nested_attributes_for

form_for

fields_for

build


Model

ユーザーは1対1でアドレス情報を持ちます。

ポイントはaccepts_nested_attributes_forを記載している点です。

accepts_nested_attributes_forについて詳しくは以下を読んでみてください。

簡単に説明すると、親モデルを通じてネストしたモデルの関連レコードの登録・更新を可能にするメソッドです。

Nested Models


user.rb

class User < ApplicationRecord

has_one :address
accepts_nested_attributes_for :address
end


address.rb

class Address < ApplicationRecord

belongs_to :user
end

これでモデル部分は完了です。次はコントローラ部分に移りましょう!


Controller

ここでのポイントは2つです。

①buildメソッドの活用

②strong parameterにattributesを用いて、address_attributesを追記

それぞれ説明していきます。

①userはhas_oneでaddressを持っています。

そのため今回はUserのオブジェクトを作成すると同時にAddressのオブジェクトを作成します。

has_oneのリファレンスを読んでみましょう。

has_oneリファレンス

ここに記載されているbuild_associationに注目してください。


新しいオブジェクトを作成

引数にはオブジェクトを生成するのに必要なパラメータを指定

この時点では保存されない


と記載されています。

そのため今回newアクションでUserのオブジェクトを作成すると同時にAddressのオブジェクトを作成するために

@user.build_addressを記載します。

②has_oneのリファレンスに


引数にはオブジェクトを生成するのに必要なパラメータを指定


とあるため、strong parameterにaddress_attributesを追記してあります。


users_controller.rb

class UsersController < ApplicationController

def index

end

def new
@user = User.new
@user.build_address
end

def create
@user = User.new(user_params)
@user.save
redirect_to users_path(@user)
end

private

def user_params
params.require(:user).permit(:name, address_attributes:[:id, :postal_code, :prefecture, :municipality, :address_number])
end

end


これでコントローラは完了です。最後にViewに移りましょう!


View

ここでのポイントはfields_forメソッドの部分になります。

fields_forはform_for内で異なるモデルを編集できるようにするメソッドです。

<%= fields_for(モデル) do |i| %>

<% end %>


の形で使用する事ができます。


new.html.erb

<%= form_for @user, url: users_path do |f| %>

<div class="form-user">
<%= f.label :name, "名前" %>
<%= f.text_field :name %>
</div>
<%= f.fields_for :address do |i| %>
<div class="form-group">
<%= i.label :postal_code, "郵便番号" %>
<%= i.text_field :postal_code %>
<br>
<%= i.label :prefecture, "都道府県" %>
<%= i.text_field :prefecture %>
<br>
<%= i.label :municipality, "市区町村" %>
<%= i.text_field :municipality %>
<br>
<%= i.label :address_number, "番地" %>
<%= i.text_field :address_number %>
</div>
<% end %>
<%= f.submit "送信" %>
<% end %>

以上でViewは完了です。

以下の内容で登録してみました。

パラメーターを確認してみましょう。

Parameters: {"utf8"=>"✓", "authenticity_token"=>"osNERk3el8wLyIWkNxSaCamany+VKi12RQo+FUH6n1Ec/IvhwcnBufZFtOEQPI4nQkxYTnjGHcH6qukheKTVpg==", 

"user"=>{"name"=>"テスト", "address_attributes"=>{"postal_code"=>"1234567", "prefecture"=>"東京都", "municipality"=>"多摩市一ノ宮", "address_number"=>"2-4"}}, "commit"=>"送信"}

User Create (11.4ms) INSERT INTO `users` (`name`, `created_at`, `updated_at`) VALUES ('テスト', '2019-01-14 16:45:46', '2019-01-14 16:45:46')

Address Create (0.4ms) INSERT INTO `addresses` (`postal_code`, `prefecture`, `municipality`, `address_number`, `created_at`, `updated_at`, `user_id`) VALUES ('1234567', 0, '多摩市一ノ宮', '2-4', '2019-01-14 16:45:46', '2019-01-14 16:45:46', 3)

きちんとuserのハッシュの中addressの情報も含まれていますね。

以上です!


参考記事

Railsで1つのフォームで複数のモデルを登録・更新させる

Active Record Nested Attributes

has_oneリファレンス

fields_forリファレンス