【Rails】deviseのコントローラを独自にカスタマイズする方法
簡単に認証機能を実装することができるdeviseですが、独自にカスタマイズしたいと思うことが多々あります。
今回は、deviseのコントローラを独自にカスタマイズする方法をご紹介します。
ルーティングの設定を行う
routesファイルに、カスタマイズしたい機能のルーティングを記述します。
例えば、deviseのユーザ登録機能とログイン・ログアウト機能をカスタマイズしたい場合は、以下のように「registrations」と「sessions」のルーティングを記述します。
devise_for :users, controllers: { registrations: 'users/registrations', sessions: 'users/sessions', }
この記述により、ユーザ登録機能(registrations)とログイン・ログアウト機能(sessions)へのアクセスがあった場合は、/app/controllers/users配下の、registrations_controller.rb、sessions_controller.rbが参照されるようになります。
カスタマイズしたい機能のみ、routesファイルに記述してください。
例1:パスワードを忘れたとき用の機能(passwords)をカスタマイズしたい時
devise_for :users, controllers: { passwords: 'users/passwords', }
例2:ログイン・ログアウト機能(sessions)とアカウントブロック解除機能(unlocks)をカスタマイズしたい時
devise_for :users, controllers: { sessions: 'users/sessions', unlocks: 'users/unlocks', }
では、ルーティングの記述がない場合どうなるのでしょうか。仮に、以下のようにregistrations: ‘users/registrations’やsessions: ‘users/sessions’の記述をなくした場合は、gemライブラリのコントローラが参照されます。
devise_for :users, controllers: { }
ユーザ登録機能(registrations)のurlへアクセスがあった場合は、gemのdeviseファイルであるregistrations_controller.rbが参照されます。
gemのdeviseファイルとは、/vender/bundle/ruby/XXX/gems/devise-XXX/ 配下に格納されているファイル群です。(※ XXXは、rubyのバージョンとdeviseのバージョンが入ります。)
コントローラに独自ロジックを記述する
完全に独自ロジックにしたい場合
deviseにデフォルトに用意されている機能を、完全に自分独自のロジックに変更したい場合は、変更したいメソッドに記述された「super」の記述をコメントアウトし、独自ロジックを記述します。例えば、ユーザ登録機能(registrations)の「create」メソッドをカスタマイズするには、以下のように記述します。
/app/controllers/users/registrations_controller.rbclass Users::RegistrationsController < Devise::RegistrationsController # GET /resource/sign_up def new super end # POST /resource def create #super #独自ロジックを記述 end ・ ・ ・
【参考】superメソッドって何?
superメソッドは、スーパークラスのメソッドを呼び出すメソッドです。superメソッドを実行すると、スーパークラス(ここでは1行目に記載されているDevise::RegistrationsController)の中で、その呼び出されたメソッドと同じメソッド名を持つメソッドを探して実行します。superメソッドが「create」メソッド内で呼ばれた場合は、スーパークラスの「create」メソッドを探して実行します。
Devise::RegistrationsControllerクラスは、/vender/bundle/ruby/XXX/gems/devise-XXX/app/controllers/devise/registrations_controller.rbファイルに記載されています。
(※XXXは、rubyのバージョンとdeviseのバージョンが入ります。)
実際に呼び出されているコードをみて見ると、同名のnewメソッドや、createメソッドが存在していることが分かります。
class Devise::RegistrationsController < DeviseController ・ ・ ・ # GET /resource/sign_up def new build_resource yield resource if block_given? respond_with resource end # POST /resource def create build_resource(sign_up_params) resource.save yield resource if block_given? if resource.persisted? if resource.active_for_authentication? set_flash_message! :notice, :signed_up sign_up(resource_name, resource) respond_with resource, location: after_sign_up_path_for(resource) else set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}" expire_data_after_sign_in! respond_with resource, location: after_inactive_sign_up_path_for(resource) end else clean_up_passwords resource set_minimum_password_length respond_with resource end end ・ ・ ・
superメソッドで実際に実行されているコードは、このDevise::RegistrationsControllerクラスに記載されたnewメソッドやcreateメソッドになります。
devise機能の一部分のみを、独自ロジックにしたい場合
一部分のみを独自ロジックにしたい場合は、以下の流れで行います。
- カスタマイズしたいメソッドをgemファイルからコピーする
- superメソッドをコメントアウトし、コピーしてきたメソッドを呼び出すようにする
- コピーしたメソッドを独自に修正し、カスタマイズする
/vender/bundle/~/devise/registrations_controller.rbに記載されたcreateメソッドを、/controllers/users/registrations_controller.rbにコピーします。メソッド名は、deviseのメソッドであることが分かるように、devise_createとしています。
/app/controllers/users/registrations_controller.rbclass Users::RegistrationsController < Devise::RegistrationsController ・ ・ ・ # POST /resource def create super end def devise_create build_resource(sign_up_params) resource.save yield resource if block_given? if resource.persisted? if resource.active_for_authentication? set_flash_message! :notice, :signed_up sign_up(resource_name, resource) respond_with resource, location: after_sign_up_path_for(resource) else set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}" expire_data_after_sign_in! respond_with resource, location: after_inactive_sign_up_path_for(resource) end else clean_up_passwords resource set_minimum_password_length respond_with resource end end
次に、createメソッド内のsuperメソッドをコメントアウトし、コピーしてきたdevise_createメソッドを呼び出すようにします。呼び出されるdevise_createメソッド内に独自ロジックを記述します。
/app/controllers/users/registrations_controller.rbclass Users::RegistrationsController < Devise::RegistrationsController ・ ・ ・ # POST /resource def create #super devise_create end def devise_create # 独自ロジックを記述 build_resource(sign_up_params) resource.save yield resource if block_given? if resource.persisted? if resource.active_for_authentication? set_flash_message! :notice, :signed_up sign_up(resource_name, resource) respond_with resource, location: after_sign_up_path_for(resource) else set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}" expire_data_after_sign_in! respond_with resource, location: after_inactive_sign_up_path_for(resource) end else clean_up_passwords resource set_minimum_password_length respond_with resource end end
【参考】deviseファイルを直接編集したらダメ?
deviseファイルの中身をコピーしてきて、内容をカスタマイズするなら、直接gemのdeviseファイルを編集しちゃえばいいんじゃない?と思われるかもしれません。しかし、gemのdeviseファイルは直接編集してはいけません。 確かにgemのdeviseファイルを直接編集しても、同じ結果が得られます。しかし、gemは外部ライブラリのため、bundle installやbundle updateをするとファイルが上書きされ、せっかく編集した内容が消えてしまう可能性があります。また、外部ライブラリは一般的にgit管理しないため、gitで管理しているプロジェクトでは変更をコミットすることができません。 外部ライブラリを編集したい場合は、今回のように直接編集せず、別の方法を考える必要があります。