💎

【Rails】nested attributesのstrong parametersにmerge

2023/12/19に公開

基本:ActionController::Parametersにmerge

例えば、フォームからはタイトルと本文だけPOSTして、ログインユーザーのIDはサーバーサイドでセットするような場合、コントローラーのストロングパラメータを以下のような記述にすると

private
def article_params
  params.require(:article).permit(:title, :body)
	.merge(user_id: current_user.id)
end

パラメータにユーザーIDがセットされます。
{"title"=>'タイトル', "body"=>"本文", "user_id"=>1}

子レコード(nested nestedがある場合)

今度はaccepts_nested_attributes_forを利用して子レコードを一気に保存する場合で、子レコードの方にuser_idをmergeしたい。

以下のように書くといけました。
articleに対してcommentがhas_manyで紐づいている関係です(この例だとarticleを書きつつcommentを自作自演しているみたいになっていて実際のフォームとしては妙ですが)。

def article_params
  params.require(:article).permit(:title, :body, comments_attributes: [:body])
        .tap do |p|
    p[:comments_attributes].each do |k, hash|
      hash.merge!(
        user_id: current_user.id,
      )
    end
  end
end

これでストロングパラメータが以下の形になります。
{"title"=>'タイトル', "body"=>"本文", "messages_attributes"=>{"1"=>{"body"=>"本文", "user_id"=>1}}}

ちなみにtapは初知りでした。リファレンスによれば「self を引数としてブロックを評価し、self を返します。」とのことで、もともとはメソッドチェーン内で途中経過のデバッグ目的で作られたものらしいですが、色々と裏技的な使い方があるようです。

備考

環境

Ruby 3.2
Rails 7.0

参考

https://stackoverflow.com/questions/61842461/how-to-merge-nested-attributes-in-strong-params-with-has-many-association

こちらを参考にしたのですがそのまま真似してもうまくいかなかったです

Discussion