DeviseでSign upはさせないけど、ユーザ自身にパスワード変更はさせたい
今日もDevise。
READMEにも書いてある通り、Deviseは機能が複数のmoduleに分かれていて、有効にしたいmoduleを選んでいくわけだが、今回は Registerable
について。
Registerable
を有効にすると、アカウント未所持ユーザが自ら、自分のメールアドレスを入力してアカウント作成をすることができるようになる。いわゆる「サインアップ」という機能を提供してくれる。それと同時に、アカウント保持者向けに、自身のアカウントの削除や、パスワード変更の機能もある。
という便利なmoduleであるところまでは良いのだが、問題は、「サインアップや自身の削除は機能として提供したくないが、自身のパスワード変更機能は提供したい」という場合だ。この場合は、
Registerable
moduleのうち不要な機能を潰すRegisterable
moduleは使わずに、必要な機能のみを自前実装する
の2択を迫られる。今回は1の方法を取ることにする。
やりたいこと
Devise::RegistrationsController
は以下のようなactionを持っている。
- サインアップ用action
#new
#create
#cancel
- パスワード変更用action
#edit
#update
- アカウント削除用action
#destroy
この内、必要ない機能に紐づくactionを無効にするというのが、今回やりたいことになる。
本当はこうやってやりたかったけど見つからなかったパターン
本当は、routesの時点で、不要な機能に紐づくactionを全部無効にしたかった。ところが、routes用DSLである devise_for
には、action単位で無効にするオプションは存在しなかった。Controller単位の skip
はあるが、actionの指定はできなかった。
Controllerを上書きして潰す
Deviseは、「提供するControllerを継承してカスタマイズされたControllerを作る」という使い方はもともと想定されているので、これに乗る。
まずroutesに、自前Controllerを使うよう指示
devise_for :users, controllers: { registrations: 'users/registrations' }
そして、自前Controllerを実装。
class Users::RegistrationsController < Devise::RegistrationsController before_action :guard_signup!, only: %i[cancel new destroy create] private def guard_signup! raise ActionController::RoutingError, 'NOT FOUND' end end
このように、不要なactionに対して、before_actionで ActionController::RoutingError
をraiseしてやる。
これで、サインアップURLにアクセスしても404になる。