【Rails5】コメント機能でのStrongParameterの設定方法
ハッシュが2つ出てくる
私が今回実装したコメント投稿formはこんな感じ。
= form_with(model: [@post, @comment]) do |f| .form-group = f.text_area :body, placeholder: 'コメント追加.', class:'form-control' = f.submit '投稿する', class:'btn'
一見普通ですがいつもと違うのはmodel: [@post, @comment]
の部分です。普段であれば、渡すmodelは1つですが、今回は関連元、関連先の2つのインスタンスを指定します。
これによって、POSTしたときに渡されるパラメーターが以下のようになります。
Parameters: { "utf8"=>"XXX", "authenticity_token"=>"XXXXXX", "comment"=>{"body"=>"はじめまして!"}, "commit"=>"XXXXX", "post_id"=>"8" }
commentテーブルに保存するデータは、"comment"=>{"body"=>"はじめまして!"}
の"はじめまして!"
で、params.require(:comment).permit(:body)
でストロングパラメーターを作ればいいじゃないかと思うかもしれません。しかし、commentsテーブルには:post_id
のカラムもあるため、 "post_id"=>"8"
の保存も必要です。
単純な発想ではArgumentErrorになる
まず思いつくのがこのような形かもしれません。これはエラーです。
params.require(:comment, :post_id).permit(:body)
では:post_id
をpermitの方に入れてしまうのはどうでしょう?
これももちろんエラーです。:post_idは:commentの値ではありませんので。
params.require(:comment).permit(:body, :post_id)
そもそもrequire, permitとは何か
こちらの記事 RailsのStrong Parametersを調べる - Qiita で紹介されていますが、requireは以下のように定義されています。
def require(key) self[key].presence || raise(ActionController::ParameterMissing.new(key)) end
self[key]
の 部分は、アクセプター(params)の中に引数で渡したkeyのvalueが存在しているとtrueを返すようです。
他の記事ではrequire()の引数を2つ以上にしていてもいけるようなことが書かれていましたが、今回の場合はエラーとなりました(なぜだ)
引数を2つ指定 params.require(:comment, :post_id) =>ArgumentError (wrong number of arguments (given 2, expected 1)):
次にpermit()ですが
def permit(*filters) params = self.class.new filters.flatten.each do |filter| case filter when Symbol, String permitted_scalar_filter(params, filter) when Hash then hash_filter(params, filter) end end unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters params.permit! end
これははっきりと引数を複数とれることが明記されていますね。 処理も単純で渡されたパラメーターを許可するようです。
個別にStrongParameterして連結する
解決方法ですが、合わせてStrongParameterを指定することが困難でしたので、:commnetと:post_idで別個に指定し、後でmerge()でハッシュを連結しました。
class CommentsController < ApplicationController def create comment = current_user.comments.build(comment_params) comment.save 〜 end private def comment_params params.require(:comment).permit(:body).merge(params.permit(:post_id)) end end
これで一応うまくいきました。
きっともっとクールな方法があるんでしょうが思いつきませんでした。
知っている方ぜひ教えて下さい!