RailsのStrong Parametersを完全解説!ネスト・配列・ハッシュのpermit書き方パターンまとめ
生徒
「Railsのパラメータって、どうやって安全に受け取ればいいんですか?」
先生
「Railsでは、Strong Parameters(ストロングパラメータ)という仕組みを使って、受け取るパラメータを明示的に制限できます。」
生徒
「ネストされたデータや配列も扱えるんですか?」
先生
「もちろん!ネストや配列もバッチリ対応できますよ。今回はその書き方を詳しく学んでいきましょう。」
1. Strong Parameters(ストロングパラメータ)とは?
Strong Parametersとは、Railsのセキュリティ機能のひとつで、ユーザーから送られてくるパラメータのうち、どれを許可(permit)するかを明確に定義する仕組みです。これにより、意図しない値の更新や、マスアサインメント脆弱性を防ぐことができます。
マスアサインメントとは、送られてきたすべてのパラメータがモデルに一括で代入されてしまう危険な状態のこと。Strong Parametersを使えば、それを防げるのです。
2. ネストされたパラメータのpermit書き方
フォームやAPIで送られてくるデータは、ネストされた構造(入れ子構造)になっていることがあります。たとえば、以下のような場合です。
params = {
user: {
name: "山田太郎",
address: {
city: "東京",
zip: "100-0001"
}
}
}
このようなときは、次のようにpermitを記述します。
params.require(:user).permit(:name, address: [:city, :zip])
address: [:city, :zip]のように、ネストしたハッシュにはシンボルのキーと配列で許可する項目を記述します。
3. 配列のパラメータをpermitする方法
チェックボックスで複数選択された値や、タグなどの情報は配列として送られてくることがあります。例を見てみましょう。
params = {
article: {
title: "Rails入門",
tags: ["Ruby", "Rails", "Web"]
}
}
このときのpermitの書き方は以下のとおりです。
params.require(:article).permit(:title, tags: [])
tags: []のように、空の配列を渡すことで、どんな値でもOKな配列を許可する意味になります。
4. 配列の中身がハッシュの場合
さらにレベルアップした例として、「配列の中にハッシュが入っている」ケースもあります。これは複数の項目をまとめて送信する場面でよく使われます。
params = {
order: {
items: [
{ name: "りんご", quantity: 3 },
{ name: "バナナ", quantity: 5 }
]
}
}
この場合のpermitの書き方はこうなります。
params.require(:order).permit(items: [:name, :quantity])
items: [:name, :quantity]のように、配列の中のハッシュの項目を指定するだけで、複雑な構造でも簡単に許可できます。
5. ネスト+配列+ハッシュの複合パターン
次はさらに複雑な「ネストされた中に配列があり、その配列の中身がハッシュ」になっているパターンです。
params = {
customer: {
name: "佐藤花子",
contacts: {
phones: [
{ type: "自宅", number: "090-1234-5678" },
{ type: "会社", number: "03-1234-5678" }
]
}
}
}
こうした構造のときでも、permitで柔軟に対応できます。
params.require(:customer).permit(
:name,
contacts: {
phones: [:type, :number]
}
)
contacts: { phones: [:type, :number] }のように、ネストの中にある配列の中のハッシュをpermitでしっかり指定しましょう。
6. permitしないとどうなる?
Strong Parametersでpermitしないと、Railsはパラメータをフィルタして破棄します。つまり、意図的に許可しないと、モデルに値が保存されないことになります。
また、requireを忘れるとエラーが発生することもあります。
ActionController::ParameterMissing (param is missing or the value is empty: user)
このようなエラーが出たときは、params.require(:user)のように書いてあるかどうかを確認しましょう。
7. よくあるStrong Parametersの書き方パターン一覧
ここまでの内容をもとに、よく使うパターンを一覧でおさらいしておきましょう。
| パターン | permitの書き方 |
|---|---|
| 単純な属性 | .permit(:name, :email) |
| ネストされたハッシュ | .permit(address: [:city, :zip]) |
| 配列 | .permit(tags: []) |
| 配列の中のハッシュ | .permit(items: [:name, :price]) |
| ネスト+配列+ハッシュ | .permit(contacts: { phones: [:type, :number] }) |
まとめ
RailsにおけるStrong Parameters(ストロングパラメータ)は、Webアプリケーションの安全性を守るための非常に重要な砦です。開発者が「どのデータを受け取るか」をホワイトリスト形式で明示することによって、悪意のあるユーザーが管理権限などの重要なカラムを勝手に更新してしまうマスアサインメント脆弱性を未然に防ぐことができます。
基本的な使い方は require でモデル名のキーを指定し、permit で許可するカラムを並べるだけですが、実務では配列やハッシュが入り混じった複雑なデータ構造を扱うシーンが多々あります。特に、動的なフォームから送られてくる複数データの保存や、JSON形式のAPI連携では、今回紹介したネスト構造の書き方が必須スキルとなります。
データベースでの実例確認
実際にデータがどのように保存されるのか、データベースの動きを見てみましょう。例えば、ユーザー情報(users)とそれに関連するプロフィール情報(profiles)を同時に更新する場合を想定します。
実行前のusersテーブルの状態
id | name | role | email
---+----------+--------+-------------------
1 | 佐藤太郎 | user | sato@example.com
2 | 鈴木花子 | user | hana@example.com
3 | 田中健太 | admin | kenta@example.com
4 | 伊藤美咲 | user | misaki@example.com
5 | 渡辺直樹 | user | naoki@example.com
実行するSQLと更新処理
Strong Parametersで :name だけを許可し、:role(権限)を許可しない設定にしている場合、外部から role: "admin" という値が送られてきても、SQLには反映されず安全に更新されます。
-- ID 1のユーザー名を更新するが、roleは変更されない
UPDATE users
SET name = '佐藤太郎(更新済)', updated_at = CURRENT_TIMESTAMP
WHERE id = 1;
実行後のusersテーブルの状態
id | name | role | email
---+------------------+--------+-------------------
1 | 佐藤太郎(更新済) | user | sato@example.com
2 | 鈴木花子 | user | hana@example.com
3 | 田中健太 | admin | kenta@example.com
4 | 伊藤美咲 | user | misaki@example.com
5 | 渡辺直樹 | user | naoki@example.com
応用:実務で使えるパラメータ制御のサンプル
実際のコントローラ内では、以下のようにプライベートメソッドとして定義するのが一般的です。複数のネストがある場合でも、読みやすく整理して記述することを心がけましょう。
class UsersController < ApplicationController
def update
@user = User.find(params[:id])
if @user.update(user_params)
redirect_to @user, notice: '更新に成功しました'
else
render :edit
end
end
private
def user_params
# nameとemail、さらにネストされたprofile内のbio、
# そして配列形式のskill_tagsを許可する例
params.require(:user).permit(
:name,
:email,
profile: [:bio, :birthday],
skill_tags: []
)
end
end
もし、許可していないパラメータを無理やり渡そうとした場合、Railsのログには以下のような警告が表示されます。
Unpermitted parameter: :admin_flag. Context: { controller: UsersController, action: update, ... }
このログが出ているときは、permit メソッドの書き忘れがないか、あるいは意図しない攻撃を受けていないかを確認する指標になります。
先生
「さて、一通りStrong Parametersの書き方を見てきましたが、理解は深まりましたか?」
生徒
「はい!最初は permit の中に [] や {} が出てきて混乱しましたが、ハッシュなら key: [:value] 、ただの配列なら key: [] と覚えたらスッキリしました。」
先生
「その通りです。特に配列の中にハッシュが入るパターン(items: [:name, :price] など)は、ECサイトのカート機能やアンケートフォームなどで非常によく使いますよ。」
生徒
「もし、さらに深くネストされていたらどうすればいいんですか?」
先生
「基本は同じです。マトリョーシカのように、外側から順番に permit の構造を作っていけばOKです。ただ、あまりに深くなりすぎる場合は、データ構造自体を見直したほうが良いサインかもしれませんね。」
生徒
「なるほど。セキュリティを守るための大事な記述なので、書き漏らしがないように毎回ログも確認する癖をつけます!」
先生
「素晴らしいですね。もし ActionController::ParameterMissing が出たら、まずは require で指定しているキーがフロントエンドから送られてきているかを確認してみてくださいね。」