目的
Railsチュートリアル 第7章にてストロングパラメータという概念が紹介されていたので、その必要性と実装方法をまとめます。
今回開発するもの
Userモデル ユーザー
has_many: posts
idカラム: userインスタンスが作成されると自動付与される値
Postモデル ユーザーが行う投稿
belongs_to: user
contentカラム: 投稿内容
user_idカラム: 投稿とユーザーを紐づける値
表示画面
contentにテキストを入力し、送信すると新規postにcontentとuser_idが入力される。
という機能を実装します。
これを実装するためのcreateアクションをストロングパラメータを使わずに(Progate的に)書くと下記の様になります。
def create
@post = Post.new(
content: params[:content],
user_id: @current_user.id
)
end
このとき@current_userは、現在ログイン中のユーザーを意味し、application_controllerで定義されています。
ビューファイルではform_withを使って、下記のように表現します。
<%= form_with model: @post, url: "/posts/create", method: :post, local: true do |f| %>
<%= f.label :content %>
<%= f.text_area :content %>
<%= f.submit "送信" %>
<% end %>
このとき、ユーザーはcontent情報のみを記入し、user_idは記入していないことがポイントです。
ストロングパラメータの必要性
テキストエリアに入力された値はparamsによって取得されます。
このとき、paramsに不正な値が含まれる可能性があります。
例えばparamsにadmin = 1のような値を入れ込まれると、Webサイトの管理者権限を奪われてしまい、セキュリティ的に問題が発生します。
ここでストロングパラメータを使うと指定した属性以外がparamsに入れられるのを防ぐことができます。
ストロングパラメータを使った記載方法
ストロングパラメータを使ったcreateアクションの記載方法は以下です。
def create
@post = Post.new(post_params)
end
private
def post_params
params.require(:post).permit(:content).merge(user_id: @current_user.id)
end
createアクションでは@postを定義しています。
@postはPostモデルのインスタンスを新たに作成し、そのキーと値はpost_paramsを使用します。
post_paramsはコントローラ内で定義されます。
このとき、privateで保護することで、このコントローラ外でpost_paramsが使用されるのを防ぎます。
さて、post_paramsはparamsに対してどのようなメソッドが使われているのかを順番に見ていきましょう。
(やっと本題)
requireはデータをまとめるハッシュ
requireメソッドはPost.newを送るデータをまとめるハッシュの要素を示します。
RailsではPost.newで送られるデータはparams[:post]というハッシュにまとめて送っており、このハッシュの要素がrequireメソッドで指定されます。
permitは入力フォームで記入する値
ユーザーが実際に入力する項目をpermit内で指定します。
今回の例だとcontent属性の値を記入するので、permit(:content)としています。
mergeは裏で渡す値
インスタンスの属性には含めるけどユーザーが記入しない項目はmerge内で指定します。
今回の例でいうと、ユーザーは投稿時に自分のユーザーidを記入しませんが、@postにはuser_idが値として付与されます。
このように裏で渡す値を扱う場合はmergeを使用します。
複数の属性を渡すときは,で区切る
例えば今、投稿時にユーザーがcontent以外にgenreという属性も記入するとします。
このときのpost_paramsは
def post_params
params.require(:post).permit(:content, :genre).merge(user_id: @current_user.id)
end
と、,で区切ります。
まとめ
ProgateでRailsを一通り勉強した後、自分で簡単な投稿サイトを作成しました。
その後Railsチュートリアルで勉強し直したところ、より現場に近い設計思想をもとに話が進んでいると感じました。
自分で作った投稿サイトをProgateレベルからRailsチュートリアルレベルにリファクタリングする上で、知識が定着する感覚を得られました。