devise
api
アプリ開発
Rails5

rails5 apiモードで、deviseとdevise_token_authを両方とも使いたかった欲張りな人の話

More than 1 year has passed since last update.


背景

ネイティブアプリが使う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で次の設定をしています。


app/controllers/application_controllers.rb


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/application.rb

config.middleware.use ActionDispatch::Flash



  1. undefined method `protect_against_forgery?' for # に対して

次にでてくるエラーはこれかと思います。ここまでは先ほどの方の記事と同じです。csrf対策をしないといけないので、親のコントローラーを変更してあげます。


config/initializes/devise.rb

config.parent_controller = 'ActionController::Base'



strong parameterでエラーが出る


  1. のエラーを解消すると、deviseはapplication_controllers.rbを経由せずに、直接ActionController::Baseを継承するようになります。そのため、前提の部分で定義していた、strong parameterへの追加の部分が読み込まれなくなります。これを解消するのが地味に大変でした。

色々試行錯誤をした結果、devise_token_authのリセット用のコントローラーをoverrideする形で解決することにしました。次のように書いてあげれば、同様にこのエラーを解消できるかと思います。


app/controllers/registrations_controller.rb

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%あるはずなので、教えて頂けると幸いです。