子レコードを同時保存する「accepts_nested_attributes_for」

f:id:ryoutaku_jo:20190327203322p:plain

【結論】

・「accepts_nested_attributes_for」は
 モデルのアソシエーションのオプション

・このメソッドを親モデルに定義すると
 データを保存した際に
 アソシエーション先の子レコードも
 同時に保存が行える

【目次】

【本題】

関連モデルにも同時保存がしたい場合

あるモデルのデータを保存した際、
その子モデルも同時に情報を保存したい場合があります。

例えば、下記の様な
アソシエーションが組まれたテーブルがあったとします。

Post(1) <<<  >>> PostState(多)

Postという親モデルに、投稿した情報が記録されており、
その子モデルであるPostStateに、投稿の更新情報が都度記録されています。

この場合、下記の様に@post.saveの後に、
@post_stateを保存する記述をする方法があります。

def create
  @post = Post.new(post_params)
  if @post.save
    @post_state = PostState.new(post_id: post.id, description: messege)
    @post_state.save
    redirect_to post_path
  else
    render :new
  end
end

private

def post_params
      params.require(:post).permit(:id, :title, :body)
end

但し、この場合updateにも同様の記述をする必要があったりと
冗長なコードになってしまいます。

そこで登場するのが「accepts_nested_attributes_for」です

「accepts_nested_attributes_for」について

「accepts_nested_attributes_for」は、
モデルに記述するオプションの一種です。

これを親モデルに記述すると、親モデルを保存した際、
アソシエーション先の子モデルの保存も一緒に実行されます。

実装方法は、下記の様に親モデルに記述します。

class PostsController < ApplicationController
  has_many :post_state, dependent: :destroy
  accepts_nested_attributes_for :post_state

後は、親モデルに渡すストロングパラメータに
子モデルに保存する情報も追記すれば、実装完了です

def create
  @post = Post.new(post_params)
  if @post.save
    redirect_to post_path
  else
    render :new
  end
end

private

def post_params
      params.require(:post).permit(:id, :title, :body, :description)
end

見た目もスッキリして、管理しやすくなりました。

参考リンク

api.rubyonrails.org

《今日の学習進捗(3年以内に10000時間に向けて)》

学習開始からの期間 :110日
今日までの合計時間:1030h
一日あたりの平均学習時間:9.4h
今日までに到達すべき目標時間:1005h
目標との解離:25h
「10,000時間」まで、

残り・・・「8970時間!」