背景
ネイティブアプリが使うapiをrails apiモードで書いてた。初めはwebサイト側で何かしら書く必要なんて無いと思ってたんだけど、よく考えたらパスワードのリセットとかのプロセスをwebサイトで書く必要があることに気づいてとても焦った話です。一通り調べてもぴったりと解決に導いてくれた記事がないのでまとめてました。
大まかな流れはこの記事と同じなんだけど、自分の場合は「エラーその2」の後に、まだハマるポイントがあったのでその補強になればと思ってます。
一応認証には、devise_token_authを使っている。devise側が
api only appではdeviseじゃなくて、devise_token_auth使ってください
ってお願いしてる関係もあってdevise_token_authを使うことにしました。
deviseでviewを作りたかったのは、passwordをリセットするところの入力フォームのみ。これだけのためにすごくハマったから、もしかしたら別の効率のいいやり方があるのかもしれません。rails歴たかが2ヶ月の自分としては、0から実装には踏み切れなかったのですが、これは少し反省してます。笑
前提
devise_token_authで追加のパラメタを許可する必要があったので、そのinitiallizerで次の設定をしています。
class ApplicationController < ActionController::API
include DeviseTokenAuth::Concerns::SetUserByToken
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:additonal, :params])
end
end
問題点
Rails5 + APIモードで後からdeviseを使おうとした時のエラー対応にもあるように、apiモードでdeviseのviewを呼び出そうとすると色々問題が発生します。csrf対策とかはapiモードには組み込まれていないし、、
この方の書かれている通りに、実装するとdevise_token_authでsign_upをしようとした時にエラーがでます。なので、以下の通りに実装してください。
1. undefined method 'flash' for#ActionDispatch::Request に対して
まずこのエラーが出ると思います。flashメッセージが出ないみたいなので、それ用のmodule(?)を追加してあげます。
config.middleware.use ActionDispatch::Flash
- undefined method `protect_against_forgery?' for # に対して
次にでてくるエラーはこれかと思います。ここまでは先ほどの方の記事と同じです。csrf対策をしないといけないので、親のコントローラーを変更してあげます。
config.parent_controller = 'ActionController::Base'
strong parameterでエラーが出る
- のエラーを解消すると、deviseはapplication_controllers.rbを経由せずに、直接ActionController::Baseを継承するようになります。そのため、前提の部分で定義していた、strong parameterへの追加の部分が読み込まれなくなります。これを解消するのが地味に大変でした。
色々試行錯誤をした結果、devise_token_authのリセット用のコントローラーをoverrideする形で解決することにしました。次のように書いてあげれば、同様にこのエラーを解消できるかと思います。
class RegistrationsController < DeviseTokenAuth::RegistrationsController
# GET /users/sign_up
def create
super
@resource = resource_class.new(sign_up_params)
end
private
def sign_up_params
params.permit(
:add,
:additional,
:params,
:wanna,
:permit
)
end
end
これが僕の考えた中では最適なやり方でした。もっといいやり方は100%あるはずなので、教えて頂けると幸いです。