[rails]Strong Parametersでhashを許可する場合のやり方


Rails4.1.7, Ruby2.1.4 で確認。

Rails4より導入されたMass Assignment脆弱性を防ぐための仕組みがStrong Parametersです。

def create
  @user = User.new(permitted_params)
end

private

def permitted_params
  params.permit(:name, :email)
end

こんな感じでコントローラで許可したパラメータのみをmodelに渡すことができます。

なお、許可されていないパラメータを渡した場合は無視されます。
(例外を投げるように変更することも可能)

このStrong Parametersでhashを許可する場合、2通りのやり方がありました。

例として

location = { x: 10, y: 20 }

というhashをパラメータとして送った場合、

1. hashの内容も厳密にチェックする場合

def permitted_params
  params.permit(:name, :email, location: [:x, :y])
end

というようにlocationをキーにして、許可するパラメータ(x, y)のシンボルを配列に記述します。

この場合は、新たにzキーを追加して

location = { x: 10, y: 20, z: 30 }

としてリクエストを行っても、zの値は無視されてしまうので注意が必要です。

p permitted_params[:location]
=> {"x"=>10, "y"=>10}

2. hashであれば内容自体はチェックしない場合

hashではあるけどhashのキーに何がくるかは厳密にチェックしなくてもいい、という場合はホワイトリストに追加することで対応できました。

def permitted_params
  params.permit(:name, :email).tap do |whitelisted|
    whitelisted[:location] = params[:location] if params[:location].is_a?(Hash)
  end
end

Object#.is_a?(Hash) でhashかどうかのチェックをして、hashだったらそのまま許可しています。

この場合は、新たにzキーを追加して

location = { x: 10, y: 20, z: 30 }

としてリクエストを行った場合は、zの値も取得できます。

p permitted_params[:location]
=> {"x"=>10, "y"=>10, "z"=>30}

以上、Strong Parametersでhashを許可する場合のやり方でした。

参考