背景
- Rails8が登場して
params.expect
を使用する機会があったので、色々調べたアウトプットをします
params.expect
とは
Rails7ではparams.require
やparams.permit
を使用して、ストロングパラメータの実装を行なっていましたが、params.expect
はそれよりコード短いし、セキュリティ的にも良さげだよ
というメソッドです
使い方
従来のRailsでは、ストロングパラメータをコントローラの中で定義するときに下記の感じで書いてました
def create
@user = User.new(user_params)
if @user.save
redirect_to users_path
else
render :new, status: :unprocessable_entity
end
end
private
def users_params
params.require(:user).permit(:name, :email)
end
Rails8ではこんな感じでかけます
def create
@user = User.new(user_params)
if @user.save
redirect_to users_path
else
render :new, status: :unprocessable_entity
end
end
def update
# 省略
end
private
def users_params
params.expect(user: [:name, :email])
end
短いすね
なぜexpect
の方が良いのか
1.パラメータを改ざんされた時、返すエラーが違う
従来通りparams.require
やparams.permit
を使用した場合
def users_params
params.require(:user).permit(:name, :email)
end
パラメータを少しいじって、こんな感じのリクエストをサーバーに送信したとします。
# 更新
PATCH /user/1?user=hoge
"500 Internal Server Error"
が返ってきます
Rails8から出たparams.expect
の場合は
def users_params
params.expect(user: [:name, :email])
end
400 Bad Request
を返します。
400と500どっちもエラーなのに、500はなぜゆえダメなのか
- 500エラーがダメな理由
- ユーザー体験の低下: サーバー内部の問題を示すため、クライアントに対して具体的なエラーメッセージを提供されない。どこで何が起きてるかわからなくなる
- セキュリティリスク: サーバー内部の問題を示すため、悪いやつがその脆弱性を攻撃してくるかも
- 400エラーが良い理由
- ユーザー体験の向上: 具体的にどこが悪いのか教えてくれる。どうすれば解決するのかがわかる状態
- セキュリティの向上: クライアントのリクエストが不正なので、サーバー側の問題が露呈しにくい
※ permit require
とexpect
を比較した時の話です
2.パタメータの型チェックをしてくれる
従来のparams.permit
では型のチェックをしてくれませんでした
仮にusers_params
を下記に設定したとします。
def users_params
params.permit(user: [:name])
end
意図としては、:name
は配列のみを許可したい感じです。
しかし、これだと
@user = User.new(user: { name: 'hoge' })
これでも通ってしまいます。
ではRails8のparams.expect
では
def users_params
params.expect(user: [[:name]])
end
「二重配列」構文で明示的に配列のみを指定することで、配列だけを許可するという書き方ができます。
仮に
@user = User.new(user: { name: 'hoge' })
を渡してあげると"400 Bad Request"
が出るようになります。
感想
- 短いコードかつ、セキュリティが高くなる方が良いに決まっているので、こっち使おうと思った。
- 意外と知らないことがたくさんあったのでボリュームあった
参考