LoginSignup
71
76

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-01-14

概要

アソシエーションで紐付いている複数のモデルへのデータ登録に苦労したのでまとめておきます。
一つの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は完了です。

以下の内容で登録してみました。
スクリーンショット 0031-01-15 1.45.40.png

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

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リファレンス

71
76
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
71
76