53
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】fields_forでbuildするときは、親子関係が「has_many」か「has_one」で方法が違うので気をつけよう!

Last updated at Posted at 2020-02-02

ミナミ(@minami_nakasato)です。

🔶今回の目標🔶

親子関係にある

Aテーブル/モデル(親)
Bテーブル/モデル(子)

これら2つに対して、同じビュー内のフォームからデータを登録しよう!

🔶やり方🔶

「一つのテーブルだけを扱うであれば
"form_for" や "form_with"
で簡単にできるけど」

「同じフォーム内で2つのテーブルのデータを変更するなんて」

「どうすればええんじゃろ〜」

そんなときに「fields_for」が役に立ちます!

今回は親である「niwatori」モデルと、子である「hiyoko」モデルを例に取り組んでみましょう💪

ステップ① モデルとマイグレーションファイルを編集

🐔親🐔

(a) モデルを作成

% rails g model Niwatori

(b) モデルファイルを編集

class Niwatori < ApplicationRecord
	belongs_to :user #注1
	has_one :hiyoko #注2
	accepts_nested_attributes_for :hiyoko #注3
end

【注1】

Niwatoriのさらに親としてuserモデルがある設定です。養鶏場のオーナーだと思ってください。

【注2】

今回はあえて「has_one」を例に出して説明します。
「has_many」を例にした説明はネット上に沢山あるけど、「has_one」を例にした説明が少ないので。

【注3】

2つのモデルがアソシエーションで結びついている時、2つまとめてレコードを更新できるRailsメソッドです。
コントローラでの記述と組み合わせて使うので、これだけではまだ未完成。

(c) マイグレーションファイルを編集

先ほど「rails g model」コマンドを実行した結果、マイグレーションファイルも生成されたので記入しましょう。

class CreateNiwatoris < ActiveRecord::Migration[6.0]
  def change
    create_table :niwatoris do |t|
      t.references :user, foreign_key: true
      t.string :niwatoriname
      t.timestamps
    end
  end
end

(d) テーブルを作成

% rails db:migrate

🐥子🐥

(a) モデルを作成

% rails g model Hiyoko

(b) モデルファイルを編集

class Hiyoko < ApplicationRecord
	belongs_to :niwatori
end

(c) マイグレーションファイルを書く

class CreateHiyokos < ActiveRecord::Migration[6.0]
  def change
    create_table :hiyokos do |t|
      t.references :niwatori, foreign_key: true
      t.string :hiyokoname
      t.timestamps
    end
  end
end

(d) テーブルを作成

% rails db:migrate

ステップ② ビューを編集する

フォームを組み込みたいファイルに以下を追記。

 = form_with model: @niwatori,local: true do |form|
   = form.text_field :niwatoriname
   = form.fields_for :hiyoko, @niwatori.build_hiyoko do |hiyoko|
     = hiyoko.text_field :hiyokoname
   = form.submit "投稿"

「fields_for」の部分を

= f.fields_for :hiyoko do |hiyoko|

にしてしまうとフォームが表示されません!
必ず上記のように

= f.fields_for :hiyoko, @niwatori.build_hiyoko do |hiyoko|

と書きましょう。

ステップ③ コントローラを編集する

class NiwatorisController < ApplicationController
  def new
    @niwatori = Niwatori.new
    @niwatori.build_hiyoko #注1
  end

  def create
    @niwatori = Niwatori.create(niwatori_params) #注2
  end

  private
    def niwatori_params
      params.require(:niwatori)
      .permit(:niwatoriname,
              hiyoko_attributes:[ #注3
              :id
              :hiyokoname
              ])
      .merge(user_id: current_user.id)
    end
end

【注1】「build」ってなに?

親モデルとアソシエーションを組んでいる子モデルのインスタンスを生成できるメソッドです。
外部キー(niwatori_id)にあらかじめ値が入ったインスタンスを作れます。

これで「fields_for」を利用したフォームがちゃんと表示されるようになりました。

ただし注意が必要!

親と子が「1 対 多」、
つまり親が子を「has_many」している場合は

親モデル.子モデル.build

と書きますが、

親と子が「1 対 1」、
つまり親が子を「has_one」している場合は
親モデル.build_子モデル
と書きましょう!

ここを間違えると、「fields_for」のフォームがビューで表示されません!

【注2】

ストロングパラメータで値を引っ張ってきましょう

【注3】

子モデルの値を受け取るために、
「fields_forの引数_attributes」
という書き方をします。

🔶まとめ🔶

これで複数のモデルを一つのフォームで変更できるようになりました🐔🐥

この記事があなたの役に立ちますように!

======================================
ミナミ(@minami_nakasato)です。都内のベンチャー企業でwebデザイン/プログラミング/動画撮影や編集などをやっています。

53
44
2

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
53
44

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?