LoginSignup
93
65

More than 5 years have passed since last update.

RailsのStrongParametersと友だちになった

Last updated at Posted at 2018-01-11

TL;DR

StrongParametersとは

StrongParameters は, requirepermit からなる Action Controller のパラメータです。

何ができるんだろう

ユーザから意図しない構造で渡ってきたパラメータに対して、コントローラおよび早期の段階で例外として処理できます。

require: 指定した値が存在しなければ例外を出す
permit: 許可してない構造のオブジェクトをパラメータから除外する

何が嬉しいんだろう

コントローラの先(モデル、ファクトリ、リポジトリなどなど)で値の構造に関する例外について考えなくてよくなります。
つまり、StrongParametersを通していれば、以降受け取った値そのものだけにフォーカスできるんです。
都度、もし値がArrayじゃなかったらどうしようとか、Hashの構造違ったらどうしようとか考えなくていい、優しい世界になるはず!

実践

require

require は必須項目のようなものです。
つまり、 require を利用すると、必要とする指定のパラメータのみを取り出すことができます。
例えば、パラメータから要求した対象の値だけをとりだすことができます。

requireで必要な情報を取る
received_json = {
  name: 'Bob',
  books: [
    { book_code: 0, title: 'Title_0' },
    { book_code: 1, title: 'Title_1' },
    { book_code: 2, title: 'Title_2' },
  ],
}

params = ActionController::Parameters.new(received_json)

params.require(:name)
# => 'Bob'

params.require(:books)
# => [
#      {"code"=>0, "title"=>"Title_0"},
#      {"code"=>1, "title"=>"Title_1"},
#      {"code"=>2, "title"=>"Title_2"},
#    ]

必要とする指定のパラメータがなければ、もちろん例外(ParameterMissing)を出します。

必要な情報がなかった。。。
params.require(:age)
# => ActionController::ParameterMissing: param is missing or the value is empty: age

permit

permit はホワイトリストのようなものです。
つまり、permit を利用すると、意図した構造以外を除外することが出来ます。
例えば下記の場合、name 以外のパラメータは意図した構造外の値になるので除外されます。

nameだけ許可するよ
received_json = {
  name: 'Bob',
  books: [
    { book_code: 0, title: 'Title_0' },
    { book_code: 1, title: 'Title_1' },
    { book_code: 2, title: 'Title_2' },
  ],
}

params = ActionController::Parameters.new(received_json)

params.permit(:name)
# Unpermitted parameters: books
# => {"name"=>"Bob"}

permit は構造を保証してくれるものなので、下記のような books 単体では除外されます。
一見すると上手くいってくれそうなものですけれどもね…

booksだけ許可するよ
params.permit(:books)
# Unpermitted parameters: name, books
# => {}

仮に、例に上げた books のような構造を許可したい時には下記のようになります。

books中のbook_codeとtitleだけ許可するよ
params.permit(:books => [:book_code, :title])
# Unpermitted parameters: name
# => {
#      "books"=>[
#        {"book_code"=>0, "title"=>"Title_0"},
#        {"book_code"=>1, "title"=>"Title_1"},
#        {"book_code"=>2, "title"=>"Title_2"}
#      ]
#    }

例に上げた params のような構造を許可したい場合は下記のようになります。

nameとbooks中のbook_codeとtitleだけ許可するよ
params.permit(:name, :books => [:book_code, :title])
# => {
#      "name"=>"Bob",
#      "books"=>[
#        {"book_code"=>0, "title"=>"Title_0"},
#        {"book_code"=>1, "title"=>"Title_1"},
#        {"book_code"=>2, "title"=>"Title_2"}
#      ]
#    }

しれっと書きましたが、実は上記のような書き方はおすすめできないです。
アロー演算子は後方にある要素全てを指し示すため、意図しない値まで差されて暴れることがあるためです。

暴れるアロー演算子
params.permit(:books => [:book_code, :title], :name)
# => SyntaxError: unexpected ')', expecting =>

なので、Object単位でカーリーブレイスでカバーしてあげましょう。

包み込まれたアロー演算子
params.permit({:books => [:book_code, :title]}, :name)
# => {
#      "name"=>"Bob",
#      "books"=>[
#        {"book_code"=>0, "title"=>"Title_0"},
#        {"book_code"=>1, "title"=>"Title_1"},
#        {"book_code"=>2, "title"=>"Title_2"}
#      ]
#    }
93
65
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
93
65