【Rails】deviseで用意したログインAPIを叩いた際、見知らぬパラメータが渡っていた

RailsにてGem deviseで認証機能を実装した際、ログイン時のpostで謎のパラメータが渡る問題に直面。
その解決法をメモします。

謎のパラメータが渡る

ログインするためのAPIを叩いたところ、エラーがかえってきました。

Processing by DeviseTokenAuth::SessionsController#create as HTML
  Parameters: {"email"=>"test1@example.com", "password"=>"[FILTERED]", "session"=>{"email"=>"test1@example.com", "password"=>"[FILTERED]"}}
Unpermitted parameter: :session

原因はUnpermitted parameter: :sessionにあると。
しかしAPIを叩く際にsessisonという名のパラメータは渡していません・・・。

Railsの仕様だった

こちらの記事に答えが書いてありました。 paramsとwrap_parameters

コントローラのparamsには、"user"というキーが自動的に付きます(値がラップされます)。これが、ActionController::ParamsWrapperの機能です。

ひえーなるほど。
つまり今回はSessionsControllerなので、sessionでラップされたパラメータも自動で用意されていたというわけです。
脱線しますがストロングパラメータを下記のように書けるのはこの機能のおかげだったのですね。

def user_params
  params.require(:user).permit(:name, :email)
end

解決方法

独自のSessionsControllerを用意する

deviseのSessionsControllerを継承した独自のコントローラーを用意。
その際にwrap_parameters format: []を差し込むことで、パラメータにsessionが入らなくなります。

class Api::V1::Auth::SessionsController < DeviseTokenAuth::SessionsController
  wrap_parameters format: []
end

ルーティングの修正

先ほど作成したコントローラーが呼ばれるように、routes.rbを修正。

Rails.application.routes.draw do
  mount_devise_token_auth_for 'User', at: 'api/v1/auth', controllers: {
    registrations: 'api/v1/auth/registrations',
    sessions: 'api/v1/auth/sessions' #追加
  }
end

これでsessionというパラメータが入ることなく、emailpasswordでログインできました。