Rails6.1+devise の controller と view をカスタマイズできる状態にする

公開:2020/12/27
更新:2020/12/27
13 min読了の目安(約12100字TECH技術記事

前回の続きです。

TL;DR

下記記事などとやってることと大差ないです。
ただ、コントローラー生成後にどう編集するとか
生成された controller や view の解説などをしっかりめに書いてる記事が見当たらなかったので
その辺りは丁寧めに書いてみました。

今回やること、やらないこと

  • やること
    • devise のビューとコントローラーのカスタマイズ
  • やらないこと
    • ビューの見た目をきれいにする

準備

前回に引き続き appコンテナ のターミナルで作業を進めます。
docker-compose down でコンテナを落としてしまっていたら、再度

docker-compose run --rm --service-ports app bash

で app コンテナのターミナルにログインしておきましょう。

コマンドでサクッと準備する

bundle exec rails g devise:views users
bundle exec rails g devise:controllers users して
必要なものを生成しましょう。
(前回、 bundle install 時に --path vendor/bundle をなくしたときは、以下のコマンドで bundle exec としている部分は bundle exec なしで実行してください)

$ bundle exec rails g devise:views users
Running via Spring preloader in process 10924
      invoke  Devise::Generators::SharedViewsGenerator
      create    app/views/users/shared
      create    app/views/users/shared/_error_messages.html.erb
      create    app/views/users/shared/_links.html.erb
      invoke  form_for
      create    app/views/users/confirmations
      create    app/views/users/confirmations/new.html.erb
      create    app/views/users/passwords
      create    app/views/users/passwords/edit.html.erb
      create    app/views/users/passwords/new.html.erb
      create    app/views/users/registrations
      create    app/views/users/registrations/edit.html.erb
      create    app/views/users/registrations/new.html.erb
      create    app/views/users/sessions
      create    app/views/users/sessions/new.html.erb
      create    app/views/users/unlocks
      create    app/views/users/unlocks/new.html.erb
      invoke  erb
      create    app/views/users/mailer
      create    app/views/users/mailer/confirmation_instructions.html.erb
      create    app/views/users/mailer/email_changed.html.erb
      create    app/views/users/mailer/password_change.html.erb
      create    app/views/users/mailer/reset_password_instructions.html.erb
      create    app/views/users/mailer/unlock_instructions.html.erb
      invoke  Devise::Generators::SharedViewsGenerator
      create    app/views/users/shared
      create    app/views/users/shared/_error_messages.html.erb
      create    app/views/users/shared/_links.html.erb
      invoke  form_for
      create    app/views/users/confirmations
      create    app/views/users/confirmations/new.html.erb
      create    app/views/users/passwords
      create    app/views/users/passwords/edit.html.erb
      create    app/views/users/passwords/new.html.erb
      create    app/views/users/registrations
      create    app/views/users/registrations/edit.html.erb
      create    app/views/users/registrations/new.html.erb
      create    app/views/users/sessions
      create    app/views/users/sessions/new.html.erb
      create    app/views/users/unlocks
      create    app/views/users/unlocks/new.html.erb
      invoke  erb
      create    app/views/users/mailer
      create    app/views/users/mailer/confirmation_instructions.html.erb
      create    app/views/users/mailer/email_changed.html.erb
      create    app/views/users/mailer/password_change.html.erb
      create    app/views/users/mailer/reset_password_instructions.html.erb
      create    app/views/users/mailer/unlock_instructions.html.erb
$ bundle exec rails g devise:controllers users
Running via Spring preloader in process 10933
      create  app/controllers/users/confirmations_controller.rb
      create  app/controllers/users/passwords_controller.rb
      create  app/controllers/users/registrations_controller.rb
      create  app/controllers/users/sessions_controller.rb
      create  app/controllers/users/unlocks_controller.rb
      create  app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================

Some setup you must do manually if you haven't yet:

  Ensure you have overridden routes for generated controllers in your routes.rb.
  For example:

    Rails.application.routes.draw do
      devise_for :users, controllers: {
        sessions: 'users/sessions'
      }
    end

===============================================================================

生成されたものの解説

$ bundle exec rails g devise:views users
今回使う 概要 path
共通で使うもの app/views/users/shared 配下
ユーザー登録確認メール後 app/views/users/confirmations 配下
パスワードを忘れたとき〜のやつ app/views/users/passwords 配下
サインアップ(パスワード登録),パスワード編集など app/views/users/registrations 配下
ログイン,ログアウト app/views/users/sessions 配下
各機能で送信されるHTMLメール本文 app/views/users/mailer 配下
$ bundle exec rails g devise:controllers users
今回使う 概要 path
ユーザー登録確認メール後 app/controllers/users/confirmations_controller.rb
パスワードを忘れたとき〜のやつ app/controllers/users/passwords_controller.rb
サインアップ(パスワード登録),パスワード編集など app/controllers/users/registrations_controller.rb
ログイン,ログアウト app/controllers/users/sessions_controller.rb
ブロック解除機能 app/controllers/users/unlocks_controller.rb
× OmniAuth のコールバック app/controllers/users/omniauth_callbacks_controller.rb

生成されたコントローラーのコメントを外す

bundle exec rails g devise:controllers users で生成されたコントローラーは
全てコメントアウトされています。
使用するコントローラーのコメントを外して使える状態にしましょう。
ついでなので生成された時のコメントを翻訳しておきました。
あとさらについでなので、本当に生成したコントローラーが叩かれているか確認するための puts をいくつか追加しておきました。
自身でもっと確認したいときは適宜 puts を追加したりしてください。

また、生成されたコントローラー内にあるコメントの

# GET /resource/sign_in

など /resource となっている部分は、それぞれ生成対象とした resource のことですよ、
という意味です。
なので今回は /resource/user を指していますね。
# GET /resource/sign_in であれば # GET /users/sign_in です。
同様に該当のコメント部分は編集してあります。

では、生成されたコントローラーのコメントを外していきましょう。

app/controllers/users/confirmations_controller.rb
# frozen_string_literal: true

class Users::ConfirmationsController < Devise::ConfirmationsController
  # GET /users/confirmation/new
  def new
    super
  end

  # POST /users/confirmation
  def create
    super
  end

  # GET /users/confirmation?confirmation_token=abcdef
  def show
    super
  end

  protected

  # 確認指示を再送した後に使用する path
  def after_resending_confirmation_instructions_path_for(resource_name)
    super(resource_name)
  end

  # 確認後に使用する path
  def after_confirmation_path_for(resource_name, resource)
    super(resource_name, resource)
  end
end
app/controllers/users/passwords_controller.rb
# frozen_string_literal: true

class Users::PasswordsController < Devise::PasswordsController
  # GET /users/password/new
  def new
    super
  end

  # POST /users/password
  def create
    super
  end

  # GET /users/password/edit?reset_password_token=abcdef
  def edit
    super
  end

  # PUT /users/password
  def update
    super
  end

  protected

  def after_resetting_password_path_for(resource)
    super(resource)
  end

  # リセットパスワードの指示を送信した後に使用する path
  def after_sending_reset_password_instructions_path_for(resource_name)
    super(resource_name)
  end
end
app/controllers/users/registrations_controller.rb
# frozen_string_literal: true

class Users::RegistrationsController < Devise::RegistrationsController
  before_action :configure_sign_up_params, only: [:create]
  before_action :configure_account_update_params, only: [:update]

  # GET /users/sign_up
  def new
    super

    puts '========================='
    puts 'GET /resource/sign_up'
    puts '========================='
  end

  # POST /users
  def create
    super
  end

  # GET /users/edit
  def edit
    super

    puts '========================='
    puts 'GET /resource/edit'
    puts '========================='
  end

  # PUT /users
  def update
    super
  end

  # DELETE /users
  def destroy
    super
  end

  # GET /users/cancel
  # 通常はサインイン後に
  # 期限切れになるセッションデータを強制的に今すぐ期限切れにします。
  # これは、ユーザーがすべての OAuth セッションデータを削除して、
  # 途中で oauth サインイン/アップをキャンセルしたい場合に便利です。
  def cancel
    super
  end

  protected

  # 許可するための追加のパラメータがある場合は、sanitizer に追加してください
  def configure_sign_up_params
    devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
  end

  # 許可するための追加のパラメータがある場合は、sanitizer に追加してください
  def configure_account_update_params
    devise_parameter_sanitizer.permit(:account_update, keys: [:attribute])
  end

  # サインアップ後に使用する path
  def after_sign_up_path_for(resource)
    super(resource)
  end

  # アクティブでないアカウントのサインアップ後に使用する path
  def after_inactive_sign_up_path_for(resource)
    super(resource)
  end
end
app/controllers/users/sessions_controller.rb
# frozen_string_literal: true

class Users::SessionsController < Devise::SessionsController
  before_action :configure_sign_in_params, only: [:create]

  # GET /users/sign_in
  def new
    super

    puts '========================='
    puts 'GET /resource/sign_in'
    puts '========================='
  end

  # POST /users/sign_in
  def create
    super
  end

  # GET /users/sign_out
  # ここは config/initializers/devise.rb で config.sign_out_via = :get としているので DELETE ではなく GET
  def destroy
    super
  end

  protected

  # 許可するための追加のパラメータがある場合は、sanitizer に追加してください
  def configure_sign_in_params
    devise_parameter_sanitizer.permit(:sign_in, keys: [:attribute])
  end
end
app/controllers/users/unlocks_controller.rb
# frozen_string_literal: true

class Users::UnlocksController < Devise::UnlocksController
  # GET /users/unlock/new
  def new
    super
  end

  # POST /users/unlock
  def create
    super
  end

  # GET /users/unlock?unlock_token=abcdef
  def show
    super
  end

  protected

  # パスワードのロック解除指示を送信した後に使用する path
  def after_sending_unlock_instructions_path_for(resource)
    super(resource)
  end

  # リソースのロックを解除した後に使用する path
  def after_unlock_path_for(resource)
    super(resource)
  end
end

生成されたコントローラーを使用するように config/routes.rb を編集する

これを

config/routes.rb
# 前回の作業が終わった状態の config/routes.rb
Rails.application.routes.draw do
  devise_for :users
  get 'home/index'
  get 'home/show'

  root to: "home#index"

  ## 開発環境用letter_opener
  mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

こんな感じに編集します。

config/routes.rb
Rails.application.routes.draw do
  devise_for :users, :controllers => {
    :confirmations => 'users/confirmations',
    :registrations => 'users/registrations',
    :sessions => 'users/sessions',
    :passwords => 'users/passwords'
   }

  get 'home/index'
  get 'home/show'

  root to: "home#index"

  ## 開発環境用letter_opener
  mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end

難しくはないですね。

動作確認

では Rails サーバーを起動して動作確認します。

bundle exec rails s -b "0.0.0.0"

http://localhost:3000 にアクセスし、「サインイン」を押してみましょう。
rails s したターミナルに

=========================
GET /resource/sign_up
=========================
Completed 200 OK in 135ms (Views: 124.2ms | Allocations: 5207)

と出たでしょうか?
やりました! 生成したコントローラーとビューが使われるようにカスタマイズできました。
他の部分も puts を追加したりいじってみたりして
生成したコントローラーとビューが使われているか確認してみてください。

今回のリポジトリはこちらです。

参考