目的
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チュートリアルレベルにリファクタリングする上で、知識が定着する感覚を得られました。