“Could not find a valid mapping for #<User …>” only on second and successive tests

蓝咒 提交于 2019-11-30 04:29:55

Thanks to : http://blog.thefrontiergroup.com.au/2011/03/reloading-factory-girl-factories-in-the-rails-3-console/

"Devise uses a mapping between classes and routes, so when a factory built object comes through to Devise after a console reload, or a class redefinition then it will fail."

Put this in an initializer or 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

Add this line to your routes.rb

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

For future readers: I received same error, but for a different reason.

Our app had multiple user models where one derived from the other

For arguments sake:

class SimpleUser

class User < SimpleUser

In my controller I used a reference to SimpleUser (the parent class), but Devise was configured to use User (the child class).

During an invocation of Devise::Mapping.find_scope! it does .is_a? comparison against the object reference and the configured class.

Since my reference was a SimpleUser, and the configured class was User, the .is_a? fails because the comparison was asking if the Parent class is_a? Child class, which is always false.

Hope that helps someone else.

I had this error in my routes file because I had an API endpoint that I wanted to allow users to reset their passwords from, but I wanted the users to actually do the password change on the web view, which wasn't namespaced under /api

This is how I fixed the routes to make it work:

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

i know this is an old thread, but i wanted an answer to whoever else runs into this. not sure where i read this, but props to the person who posted about this on another forum.

Long and the short is that the devise test helpers don't work well with integration tests.

So remove all references for Devise::TestHelpers (some people use include, other people use require 'devise/testhelpers') from within the specs themselves.

then in the spec_helper file add:

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

Halfnelson's solution worked for me too, but since I'm using the Fabrication gem instead of FactoryGirl, I needed to make some adjustments. Here's the code I droped into a initializer:

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

Just in case anyone else runs into this, for the same reason as me - I had the same problem on basically all my tests after a change to some config files - it turned out it was due to RAILS_ENV being set to development when I ran the tests by accident. Might be worth checking before adding a test-specific rails initializer :-)

In my case this was a problem with Devis's confirm! method. So instead of doing this (Minitest::Test code):

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

I have done this:

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

And it worked :)

I had this happen to me before when I signed in as a test user on one of my apps and had made some test uploads and test posts. I then deleted that test user and when I tried to sign up again with the same test user I was displayed the message "Could not find a valid mapping for nil". What I did to solve it was to delete all of the test uploads and test post that I had made as that test user. I then tried to sign up again and it worked. By that way a faster and easier way to delete stuff is by using db browser for sqlite.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!