LoginSignup
4
1

More than 5 years have passed since last update.

deviseのcontrollerのテストで `NoMethodError: undefined method `name' for nil:NilClass` が出るとき

Last updated at Posted at 2016-12-06

起こったこと

  • deviseの registrations#new をテストしたい
  • registrations#new には管理者のみアクセス可能にして、それ以外のユーザーはルートにリダイレクトしたい
  • しかし、下記のエラーが出てうまく行かない
NoMethodError: undefined method `name' for nil:NilClass
from <hoge_hoge>/vendor/bundle/ruby/2.3.0/gems/devise-4.2.0/app/controllers/devise_controller.rb:42:in `resource_name'
  • テストコード
registrations_controller_spec.rb
require 'rails_helper'

RSpec.describe Admin::Devises::RegistrationsController, type: :controller do
  describe 'GET #new' do
    let (:response) { get :new }

    context '管理者の場合' do
      login_admin
      it 'ステータス 200 になる' do
        expect(response).to be_success
      end
    end

    context '管理者以外の場合' do
      login_writer
      it 'ステータス 300番台でホーム画面にリダイレクト' do
        expect(response).to be_redirect
        expect(response).to redirect_to root_path
      end
    end
  end
end

エラーの原因

  • まずエラーが起きている場所は下記のソース
devise_controller.rb
  # Proxy to devise map name
  def resource_name
    devise_mapping.name
  end
  • devise_mapping.namenil なのでどこかで設定をミスっている

  • deviseの wiki にヒントがあった

Every time you want to unit test a devise controller, you need to tell Devise which mapping to use. We need that because ActionController::TestCase and spec/controllers bypass the router and it is the router that tells Devise which resource is currently being accessed, you can do that with:

  • devise_controller.rb をユニットテストするたびに使用するマッピングを Devise に伝える必要がある
  • その設定は wiki の通りに controller_macros.rb に書いて上記の registrations_controller_spec.rb で呼んでいる
controller_macros.rb
module ControllerMacros
  def login_admin
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:admin]
      sign_in FactoryGirl.create(:admin)
    end
  end

  def login_writer
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:admin]
      sign_in FactoryGirl.create(:writer)
    end
  end
end
  • Devise.mappings[:admin] でマッピングするシンボルは registrations#new のルーティングが namespace などで変更されている場合、それに合わせて書き換えないといけない
  • 自分に場合、下記のようなルーティングにしていた
routes.rb
<省略>
  namespace :admin do
    devise_for :users, controllers: {
      sessions:      'admin/devises/sessions',
      registrations: 'admin/devises/registrations',
      passwords:     'admin/devises/passwords',
    }

<省略>
  • namespace :admin でマッピングするシンボルが変わるので、正しくは下記のような controller_macros.rb になる
controller_macros.rb
<省略>
      @request.env["devise.mapping"] = Devise.mappings[:admin_user]
<省略>
      @request.env["devise.mapping"] = Devise.mappings[:admin_user]
<省略>
  • とても長い時間ハマっていたので、誰かのお役に立てば良い

参考記事というか、deviseのwiki

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1