#概要
アソシエーションで紐付いている複数のモデルへのデータ登録に苦労したのでまとめておきます。
一つの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
class User < ApplicationRecord
has_one :address
accepts_nested_attributes_for :address
end
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を追記してあります。
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 %>
の形で使用する事ができます。
<%= 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つのフォームで複数のモデルを登録・更新させる]
(https://qiita.com/tmzkysk/items/6349d8d860c5982771ff)
Active Record Nested Attributes
has_oneリファレンス
fields_forリファレンス