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"}
#      ]
#    }
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.