Help us understand the problem. What is going on with this article?

RailsのStrong Parametersを調べる

More than 1 year has passed since last update.

railsを触っていたらStrong Parametersというものが出てきたので調べてみました。
初心者ですので間違っている部分ありましたらご指摘いただければと思います。:eyes:

この記事で言いたいこと

  • Strong ParametersはDBに入れる値を制限することで、不正なパラメータの入力を防ぐ仕組みであること

Strong Parametersの概要

Rails4系から追加された仕組みです。
Rails3系まではMassAssignmentを使っていたのだが、そこに脆弱性があったためStrong Parametersが導入されたとのことです。
簡単に言うとDBへ入れたり更新したりするパラメータを制限してくれる仕組みです。

MassAssignment脆弱性にまつわるニュース↓
https://www.infoq.com/jp/news/2012/03/GitHub-Compromised

基本的な使い方

例)
params.require(:user).permit(:name, :email, :password)

①requireでPOSTで受け取る値のキーを設定
②permitで許可するカラムを設定
ここではname, email, password属性の値だけDBに入れるのを許可
adminカラムとか付随してても無視します。

ちなみにstrong parametersを使ってないとrailsさん:angry:にエラーを吐かれるので注意
スクリーンショット 2017-08-25 11.32.24.png

requireとpermitを軽く読み解く

https://github.com/rails/strong_parameters/blob/master/lib/action_controller/parameters.rb
を少し見てみました。

require

parameters.rb
def require(key)
  self[key].presence || raise(ActionController::ParameterMissing.new(key))
end

presenceはrailsのObject#presenceメソッドです。
値が存在してればselfを返して、値が無ければfalseを返すようです。
requireメソッドでは、値がなければエラーを返すようになっていました。
また「[]」は以下のようにオーバーライドされており、ハッシュをパラメータに変換する機能を持たせてあります。

parameters.rb
def [](key)
      convert_hashes_to_parameters(key, super)
end

permit

parameters.rb
def permit(*filters)
  params = self.class.new

  filters.flatten.each do |filter|
    case filter
    when Symbol, String
      permitted_scalar_filter(params, filter)
    when Hash then
      hash_filter(params, filter)
    end
  end

  unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters

  params.permit!
end

こちらは実際にDBに受け渡されるパラメータを一つずつフィルターにかける作業をしているようです。
またpermitに指定されたものがハッシュだった場合も、分解されそのパラメータをフィルターに書けます。
そのフィルターではパラメータの型が許可できるものかどうかを検証してくれています。
以下のFilterlingの部分に許可するパラメータの型が設定されています。

parameters.rb
PERMITTED_SCALAR_TYPES = [
  String,
  Symbol,
  NilClass,
  Numeric,
  TrueClass,
  FalseClass,
  Date,
  Time,
  # DateTimes are Dates, we document the type but avoid the redundant check.
  StringIO,
  IO,
  ActionDispatch::Http::UploadedFile,
  Rack::Test::UploadedFile,
      ]

また、permitで指定していないパラメータはこちらで処理されます。

parameters.rb
def unpermitted_parameters!(params)  
  return unless self.class.action_on_unpermitted_parameters

  unpermitted_keys = unpermitted_keys(params)

  if unpermitted_keys.any?  
    case self.class.action_on_unpermitted_parameters  
    when :log
    name = "unpermitted_parameters.action_controller"
      ActiveSupport::Notifications.instrument(name, :keys => unpermitted_keys)
    when :raise  
      raise ActionController::UnpermittedParameters.new(unpermitted_keys)  
    end  
  end  
end  

def unpermitted_keys(params)  
  self.keys - params.keys - NEVER_UNPERMITTED_PARAMS
end

ログを取るかエラーを出すようになっています。
デフォルトではログが出るようになっており、
エラーを出力するためには別途設定する必要があります(後述)。
NEVER_UNPERMITTED_PARAMSにはrailsによって生成されるパラメータが入っており、それは除外されるようになっています。

その他のstrong parametersの使い方

ネストしたパラメータを使う時

params.require(:user).permit(:name, :email, recommend_book: [:user_id, :comment])

入れ子になったパラメータをPOSTするときはStrong Parameters側も設定しないといけないです。

指定したキーがないときにエラーを出さないようにする

params.fetch(:user, {}).permit(:name, :email, :password)

userパラメータがなかったときはActionController::ParameterMissingのエラーが起きるようになっています。
上記の設定をしてあるとuserパラメータの代わりに{}がデフォルト値として評価されるようになります。

違うパラメータが送られてきた時にエラーを出力する

各環境のconfigfileに設定します。
出力したい環境に応じて設定を記述するファイルは変えて下さい。

config/environments/development.rb
config.action_controller.action_on_unpermitted_parameters = :raise

ActionController::UnpermittedParametersエラーが出力されるようになります。

参考


mochio
lifull
日本最大級の不動産・住宅情報サイト「LIFULL HOME'S」を始め、人々の生活に寄り添う様々な情報サービス事業を展開しています。
https://lifull.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした