前回の環境構築(Macでrails newしてrails sで動かすまで)の続きとして、
やっぱりユーザー認証が必須の場合が多いので、deviseを極力シンプルに導入してみます。
Rails6。色々、変わってるのでメモしておきます。

deviseインストール

Gemfileの最終行に追加

# Use devise 
gem 'devise'
$ bundle install
$ rails g devise:install

config/environments/development.rbの39行目辺りに追加

  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

app/views/layouts/application.html.erbの13行目辺り(Bodyの中)に追加

    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>
$ rails g devise user
$ rails g devise:views users
$ rails g devise:controllers users

config/routes.rbの2行目辺りのを変更

  devise_for :users
↓
  devise_for :users, controllers: {
    sessions: 'users/sessions'
  }
$ rails db:migrate
$ rails routes
                               Prefix Verb   URI Pattern                                                                              Controller#Action
                     new_user_session GET    /users/sign_in(.:format)                                                                 devise/sessions#new
                         user_session POST   /users/sign_in(.:format)                                                                 devise/sessions#create
                 destroy_user_session DELETE /users/sign_out(.:format)                                                                devise/sessions#destroy
                    new_user_password GET    /users/password/new(.:format)                                                            devise/passwords#new
                   edit_user_password GET    /users/password/edit(.:format)                                                           devise/passwords#edit
                        user_password PATCH  /users/password(.:format)                                                                devise/passwords#update
                                      PUT    /users/password(.:format)                                                                devise/passwords#update
                                      POST   /users/password(.:format)                                                                devise/passwords#create
             cancel_user_registration GET    /users/cancel(.:format)                                                                  devise/registrations#cancel
                new_user_registration GET    /users/sign_up(.:format)                                                                 devise/registrations#new
               edit_user_registration GET    /users/edit(.:format)                                                                    devise/registrations#edit
                    user_registration PATCH  /users(.:format)                                                                         devise/registrations#update
                                      PUT    /users(.:format)                                                                         devise/registrations#update
                                      DELETE /users(.:format)                                                                         devise/registrations#destroy
                                      POST   /users(.:format)                                                                         devise/registrations#create
$ rails s
-> http://localhost:3000/users/sign_up
-> http://localhost:3000/users/edit

【参考】ここまでのコミット内容
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/7dabcb0ac075721fdee3a0658111080bf34cc3ea

動線追加

app/views/layouts/application.html.erbの13行目辺り(Bodyの中)に追加

    <ul>
<% if user_signed_in? %>
      <li><%= current_user.email %></li>
      <li><%= link_to 'Edit User', edit_user_registration_path %></li>
      <li><%= link_to 'Log out', destroy_user_session_path, method: :delete %></li>
<% else %>
      <li><%= link_to 'Log in', new_user_session_path %></li>
      <li><%= link_to 'Sign up', new_user_registration_path %></li>
<% end %>
    </ul>
    <hr/>

RSpec対応

$ rspec
Failures:

  1) TopController GET #index returns http success
     Failure/Error: <% if user_signed_in? %>
     
     ActionView::Template::Error:
       Devise could not find the `Warden::Proxy` instance on your request environment.
       Make sure that your application is loading Devise and Warden as expected and that the `Warden::Manager` middleware is present in your middleware stack.
       If you are seeing this on one of your tests, ensure that your tests are either executing the Rails middleware stack or that your tests are using the `Devise::Test::ControllerHelpers` module to inject the `request.env['warden']` object for you.

spec/rails_helper.rbの2712行目辺りに追加

# Use devise
require 'devise'

66行目辺り(endの前)に追加

  # Use devise
  config.include Devise::Test::ControllerHelpers, type: :controller
  config.include Devise::Test::ControllerHelpers, type: :view
$ rspec
2 examples, 0 failures

通った。

RSpec追加

追加した動線やメールアドレスが含まれるかのテストを追加してみます。

Gemfileのrspec-railsの34行目辺り(RSpecの所)に足りないgemがあれば追加

  # Use RSpec
  gem 'rspec-rails', '>= 4.0.0' # Tips: https://qiita.com/amatsukix/items/578f85cf4565ca2a797c
  gem 'spring-commands-rspec'
  gem 'rails-controller-testing'
  gem 'factory_bot_rails'
  gem 'faker'
$ bundle install

spec/rails_helper.rbの2712行目辺りに追加

# Use devise
require 'devise'
require File.expand_path('spec/support/controller_macros.rb')

28行目辺りの変更

# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
↓
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }

7170行目辺り(endの前)に追加

  config.include ControllerMacros, type: :controller
  config.include ControllerMacros, type: :view
  config.include FactoryBot::Syntax::Methods

spec/support/controller_macros.rbを作成

module ControllerMacros
  def login_user(user)
    allow(controller).to receive(:authenticate_user!).and_return(true)
    @request.env['devise.mapping'] = Devise.mappings[:user]
    sign_in user
  end
end

spec/factories/users.rbを作成

FactoryBot.define do
  factory :user do
    pass = Faker::Internet.password(min_length: 8)
    email                 { Faker::Internet.email }
    password              { pass }
    password_confirmation { pass }
  end
end

spec/views/layouts/application.html.erb_spec.rbを作成

require 'rails_helper'

RSpec.describe 'layouts/application', type: :view do
  let!(:user) { create(:user) }

  context '未ログイン' do
    it 'Log inのパスが含まれる' do
      render
      expect(rendered).to match(new_user_session_path)
      # これだとURLが他のURLの一部に含まれる場合に意図せず成功してしまうので修正
      # 例:/spaces/editが存在すると、/spacesがあると誤認
      expect(rendered).to match("\"#{Regexp.escape(new_user_session_path)}\"")
      # こっちの方がシンプルですね。
      expect(rendered).to include("\"#{new_user_session_path}\"")
    end
    it 'Sign upのパスが含まれる' do
      render
      expect(rendered).to match(new_user_registration_path)
      expect(rendered).to match("\"#{Regexp.escape(new_user_registration_path)}\"")
      expect(rendered).to include("\"#{new_user_registration_path}\"")
    end
  end

  context 'ログイン中' do
    before do
      login_user user
    end
    it 'ログインユーザーのメールアドレスが含まれる' do
      render
      expect(rendered).to match(user.email)
      expect(rendered).to include(user.email)
    end
    it 'Edit Userのパスが含まれる' do
      render
      expect(rendered).to match(edit_user_registration_path)
      expect(rendered).to match("\"#{Regexp.escape(edit_user_registration_path)}\"")
      expect(rendered).to include("\"#{edit_user_registration_path}\"")
    end
    it 'Log outのパスが含まれる' do
      render
      expect(rendered).to match(destroy_user_session_path)
      expect(rendered).to match("\"#{Regexp.escape(destroy_user_session_path)}\"")
      expect(rendered).to include("\"#{destroy_user_session_path}\"")
    end
  end
end
$ rspec
7 examples, 0 failures

deviceのroutingテスト追加

パス(URLの一部)と呼び出されるcontrollerの対応(config/routes.rb)が正しいかのテストだと理解。
リリース後に意図せずURLが変わるとリンク切れ等、トラブルになるのであった方が良さそう。
また、requestのテストをしなくても、以降はcontrollerのテストで担保できると。

spec/routing/users/registrations_routing_spec.rbを作成

require 'rails_helper'

RSpec.describe Users::RegistrationsController, type: :routing do
  describe 'routing' do
    it 'routes to #new' do
      expect(get: '/users/sign_up').to route_to('devise/registrations#new')
    end
    it 'routes to #create' do
      expect(post: '/users').to route_to('devise/registrations#create')
    end
    it 'routes to #edit' do
      expect(get: '/users/edit').to route_to('devise/registrations#edit')
    end
    it 'routes to #update' do
      expect(put: '/users').to route_to('devise/registrations#update')
    end
    it 'routes to #destroy' do
      expect(delete: '/users').to route_to('devise/registrations#destroy')
    end
    it 'routes to #cancel' do
      expect(get: '/users/cancel').to route_to('devise/registrations#cancel')
    end
  end
end

spec/routing/users/sessions_routing_spec.rbを作成

require 'rails_helper'

RSpec.describe Users::SessionsController, type: :routing do
  describe 'routing' do
    it 'routes to #new' do
      expect(get: '/users/sign_in').to route_to('users/sessions#new')
    end
    it 'routes to #create' do
      expect(post: '/users/sign_in').to route_to('users/sessions#create')
    end
    it 'routes to #destroy' do
      expect(delete: '/users/sign_out').to route_to('users/sessions#destroy')
    end
  end
end

spec/routing/users/passwords_routing_spec.rbを作成

require 'rails_helper'

RSpec.describe Users::PasswordsController, type: :routing do
  describe 'routing' do
    it 'routes to #new' do
      expect(get: '/users/password/new').to route_to('devise/passwords#new')
    end
    it 'routes to #new' do
      expect(post: '/users/password').to route_to('devise/passwords#create')
    end
    it 'routes to #edit' do
      expect(get: '/users/password/edit').to route_to('devise/passwords#edit')
    end
    it 'routes to #update' do
      expect(put: '/users/password').to route_to('devise/passwords#update')
    end
  end
end
$ rspec
20 examples, 0 failures

deviceの機能拡張は他を他サイトを参考にして頂ければと思いますが、
今回未使用の下記に対応するテストも必要に応じて追加した方が良さそうですね。
app/controllers/users/confirmations_controller.rb
app/controllers/users/omniauth_callbacks_controller.rb
app/controllers/users/unlocks_controller.rb

【参考】ここまでのコミット内容
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/38551c3c9a7cd08eb59af89698e7cccc0235a46e

Railsアプリにサクッとdeviseを導入” に対して1件のコメントがあります。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です