JSONでデータを送るとき、コントローラ名と送信するパラメータのキー名(name属性のプレフィクス)の関係についての話です。
UsersControllerというコントローラがあるとします。このコントローラに対して、Ajaxを使いJSON形式かつPOSTメソッド(またはPUT、PATCH)でデータを送ります。パラメータには"user"のようなキーを付けません。
Axios.post('/users.json', { name: 'Taro', email: 'taro@example.com' });
すると、コントローラのparamsには、"user"というキーが自動的に付きます(値がラップされます)。これが、ActionController::ParamsWrapperの機能です。
{"name"=>"Taro", "email"=>"taro@example.com", "user"=>{"name"=>"Taro", "email"=>"taro@example.com"}}
次のようにストロングパラメータを使っていても大丈夫、というわけです。
def user_params
params.require(:user).permit(:name, :email)
end
しかし、コントローラ名とは違うキー名を使いたい場合があります。次の例では"member"です。
Axios.post('/users.json', { member: { name: 'Taro', email: 'taro@example.com' }});
すると、コントローラのparamsには、"user"というキーが付き、中は空となります。
{"member"=>{"name"=>"Taro", "email"=>"taro@example.com"}, "user"=>{}}
これが気になるときは、wrap_parametersメソッドでキー名を指定します。このコントローラでラッピングに使われるキー名が"member"になります。
class UsersController < ApplicationController
wrap_parameters :member
あるいは、次のようにすると、JSON形式ではラップしなくなります。
class UsersController < ApplicationController
wrap_parameters format: []
コントローラすべてに適用するには、initializers下の設定ファイルで指定します。配列[:json]
を空にします。
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: []
end
実際のプロジェクトでは
一番上のサンプル(キーを付けない場合)では、値が配列やハッシュの場合はラップしてくれません。ActionController::ParamsWrapperの設定をデフォルトにしたままだと混乱を招きそうです。
新規プロジェクトではinitializers下の設定でJSONを外しておくのがいいと思います。既存のプロジェクトでは、デフォルトでオフにするのはちょっとこわいので、コントローラごとに指定しておくことにします。
そのうえで、「AjaxでPOST、PATCHするときは、パラメータにキーを付けて値をラッピングして、ストロングパラメータを使うこと」というガイドラインを作っておくとよいかと。
補足
この機能いつからあったっけと調べたら、だいぶ昔で、2011年のRails 3.1からでした。