web-dev-qa-db-ja.com

2回目以降のテストでのみ「#<ユーザー...>の有効なマッピングが見つかりませんでした」

ユーザーがログインしているかログアウトしているかに応じて、アプリケーションのレイアウトに適切なリンクが表示されることを表明するリクエストテストを作成しようとしています。 FWIW、認証部分にDeviseを使用しています。

これが私の仕様です:

require 'spec_helper'
require 'devise/test_helpers'

describe "Layout Links" do
  context "the home page" do
    context "session controls" do
      context "for an authenticated user" do
        before do
          # I know these should all operate in isolation, but I
          # want to make sure the user is explicitly logged out
          visit destroy_user_session_path

          @user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123")
          @user.confirm!

          # I tried adding this per the Devise wiki, but no change
          @request.env["devise.mapping"] = Devise.mappings[:user]

          # Now log a new user in
          visit new_user_session_path
          fill_in "Email",    :with => @user.email
          fill_in "Password", :with => "Asd123"
          click_button "Sign in"
          get '/'
        end

        it "should not have a link to the sign in page" do
          response.should_not have_selector(
            '#session a',
            :href => new_user_session_path
          )
        end

        it "should not have a link to registration page" do
          response.should_not have_selector(
            '#session a',
            :href => new_user_registration_path
          )
        end

        it "should have a link to the edit profile page" do
          response.should have_selector(
            '#session a',
            :content => "My Profile",
            :href => edit_user_registration_path
          )
        end

        it "should have a link to sign out page" do
          response.should have_selector(
            '#session a',
            :content => "Logout",
            :href => destroy_user_session_path
          )
        end
      end # context "for an authenticated user"
    end # context "session controls"
  end
end

最初のテストは合格ですが、最後の3つはすべてエラーで失敗します

Failure/Error: @user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123")
  RuntimeError:
    Could not find a valid mapping for #<User id: xxx, ...>

Devise wiki、Googleグループ、検索結果で原因を検索しましたが、config.include Devise::TestHelpers, :type => :controllerを設定するための未回答の質問または提案だけが見つかりましたが、これはコントローラーテストにのみ適用され、リクエストテストには適用されません。


更新

もう少しトラブルシューティングを行いましたが、最終的に問題を引き起こしているものの頭または尾を作ることができません。次のコードを見てください。

まず、いくつかのコンテキストのために、ここにユーザーファクトリ宣言があります。単体テストでは正常に機能します。

# spec/factories.rb
Factory.define :user do |f|
  f.email { Faker::Internet.email }
  f.email_confirmation { |f| f.email }
  f.password "AbcD3fG"
  f.password_confirmation "AbcD3fG"
  f.remember_me { (Random.new.Rand(0..1) == 1) ? true : false }
end

ここで、次の統合テストについて考えてみましょう。

# spec/requests/user_links_spec.rb
require "spec_helper"

describe "User Links" do
  before(:each) do
    # This doesn't trigger the problem
    # @user = nil

    # This doesn't trigger the problem
    # @user = User.new

    # This doesn't trigger the problem
    # @user = User.create(
    #   :email => "[email protected]", 
    #   :email_confirmation => "[email protected]", 
    #   :password => "asdf1234", 
    #   :password_confirmation => "asdf1234"
    # )

    # This doesn't trigger the problem
    # @user = User.new
    # @user.email = Faker::Internet.email
    # @user.email_confirmation = @user.email
    # @user.password = "AbcD3fG"
    # @user.password_confirmation = "AbcD3fG"
    # @user.remember_me = (Random.new.Rand(0..1) == 1) ? true : false
    # @user.save!

    # This triggers the problem!
    @user = Factory(:user)

    # This doesn't trigger the same problem, but it raises a ActiveRecord::AssociationTypeMismatch error instead. Still no idea why. It was working fine before in other request tests.
    # @user = Factory(:brand)
  end

  context "when using `@user = Factory(:user)` in the setup: " do
    2.times do |i|
      it "this should pass on the 1st iteration, but not the 2nd (iteration ##{i+1})" do
        # This doesn't trigger an error
        true.should_not eql(false)
      end

      it "this should pass on the 1st iteration, but trigger the error that causes all successive test cases to fail (iteration ##{i+1})" do
        # Every test case after this will be borken!
        get '/'
      end

      it "this will fail on all iterations (iteration ##{i+1})" do
        # This will now trigger an error
        true.should_not eql(false)
      end
    end
  end
end

コメントアウトするか、get '/'ビットを他のもの(またはまったく何もない)に置き換えると、テストはすべて正常に実行されます。

したがって、これがfactory_girlの問題(問題なしで他の場所でユーザーファクトリを使用できるため、疑う傾向があります)なのか、Deviseの問題(アプリケーションでそのgemを設定した後にこれらのエラーが発生し始めた)なのかはわかりません。しかし、他に1つのリクエストテストしかありませんでしたが、正常に機能しましたが、AssociationTypeMismatchエラー(相関≠原因...)、RSpecの問題、またはその他の奇妙なエッジケースのgemの競合が発生しています。

28
Chris Bloom

おかげで: http://blog.thefrontiergroup.com.au/2011/03/reloading-factory-girl-factories-in-the-Rails-3-console/

「Deviseはクラスとルート間のマッピングを使用するため、コンソールのリロード後、またはクラスの再定義後に、工場で構築されたオブジェクトがDeviseに到達すると、失敗します。」

これを初期化子またはapplication.rbに入れます

ActionDispatch::Callbacks.after do
  # Reload the factories
  return unless (Rails.env.development? || Rails.env.test?)

  unless FactoryGirl.factories.blank? # first init will load factories, this should only run on subsequent reloads
    FactoryGirl.factories.clear
    FactoryGirl.find_definitions
  end
end
9
Halfnelson

この行をroutes.rbに追加します

# Devise routes
devise_for :users # Or the name of your custom model
21
Bruno Paulino

将来の読者のために:私は同じエラーを受け取りましたが、理由は異なります。

私たちのアプリには複数のユーザーモデルがあり、一方が他方から派生しています

議論のために:

class SimpleUser

class User < SimpleUser

私のコントローラーでは、SimpleUser(親クラス)への参照を使用しましたが、DeviseはUser(子クラス)を使用するように構成されていました。

Devise :: Mapping.find_scopeの呼び出し中! .is_aですか?オブジェクト参照および構成済みクラスとの比較。

私の参照はSimpleUserであり、構成されたクラスはUserだったので、.is_a?親クラスがis_aかどうかを比較が尋ねていたため、失敗しましたか?子クラス。これは常にfalseです。

それが他の誰かを助けることを願っています。

9
Alex Soto

ユーザーがパスワードをリセットできるようにするAPIエンドポイントがあったため、ルートファイルでこのエラーが発生しましたが、_/api_

これは私がそれを機能させるためにルートを修正した方法です:

_CoolApp::Application.routes.draw do
  namespace :api, defaults: { format: :json } do
    devise_scope :users do
      post 'users/passwords', to: 'passwords#create'
    end

    resources :users, only: [:create, :update]
  end

  devise_for :users

  root to: 'high_voltage/pages#show', id: 'home'
end
_
3
Neal

Halfnelsonのソリューションもうまくいきましたが、FactoryGirlの代わりに Fabrication gem を使用しているため、いくつかの調整を行う必要がありました。イニシャライザにドロップしたコードは次のとおりです。

if Rails.env.development? || Rails.env.test?
  ActionDispatch::Callbacks.after do
    Fabrication.clear_definitions
    Rails.logger.debug 'Reloading fabricators'
  end
end
1
rafaelrosafu

他の誰かがこれに遭遇した場合に備えて、私と同じ理由で-いくつかの構成ファイルを変更した後、基本的にすべてのテストで同じ問題が発生しました-Rails_ENVdevelopmentに設定されていることが原因であることが判明しました誤ってテストを実行したとき。テスト固有のRails初期化子:-)を追加する前に確認する価値があるかもしれません

1
mistertim

私はこれが古いスレッドであることを知っていますが、他の誰かがこれに遭遇したときの答えが欲しかったのです。私がこれをどこで読んだかはわかりませんが、これについて別のフォーラムに投稿した人に小道具を提供します。

長短は、デバイステストヘルパーが統合テストでうまく機能しないことです。

したがって、仕様自体の中からDevise :: TestHelpers(includeを使用する人もいれば、require'devise/testhelpers 'を使用する人もいます)のすべての参照を削除します。

次に、spec_helperファイルに次を追加します。

RSpec.configure do |config|
  config.include Devise::TestHelpers, :type => :controller
end
1
mackmack

私の場合、これはDevisのconfirm!メソッドの問題でした。したがって、これを行う代わりに(Minitest::Testコード):

setup do
  @admin = create(:admin).confirm!
end

私はこれをしました:

setup do
  @admin = create(:admin)
  @admin.confirm!
end

そしてそれはうまくいきました:)

1
Bartek Skwira

以前、自分のアプリの1つでテストユーザーとしてサインインし、テストのアップロードと投稿を行ったときに、これが発生しました。次に、そのテストユーザーを削除し、同じテストユーザーで再度サインアップしようとすると、「nilの有効なマッピングが見つかりませんでした」というメッセージが表示されました。それを解決するために私がしたことは、そのテストユーザーとして作成したすべてのテストアップロードとテスト投稿を削除することでした。その後、再度サインアップしようとしましたが、うまくいきました。その方法で、ものを削除するためのより速くて簡単な方法は sqliteのdbブラウザ を使用することです。

0
AaronG