DEV Community

Débora Fernandes
Débora Fernandes

Posted on • Updated on

How-to fix: not find a valid mapping for #<User ...>

Após adicionar a confirmação de usuário em uma Rails gem:

class User < ApplicationRecord
...
  devise :confirmable
...
end

e atualizar as factories para como padrão ter um User#confirmed?
com confirmed_at { 1.day.ago }, os testes que envolviam o model User na minha aplicação passaram a quebrar de uma forma inesperada...

Could not find a valid mapping for #<User id: 1...>

Por que os testes quebraram?!

Após ativar o Devise::Confirmable, o create do objeto passa a chamar o send_confirmation_instructions.
Esse método por sua vez, depende que na rota do rails esteja configurado devise_for ou devise_scope :resource

A gem não tem o arquivo routes.rb configurado e com isso, também não tem o mapping devise_for ou devise_scope e isso que faz com que o método Devise::Mapping#find_scope! dê raise
raise "Could not find a valid mapping for #{obj.inspect}"

Could not find a valid mapping for #<User id: 1...>
     # /Users/username/.rvm/gems/ruby-2.6.6/gems/devise-4.7.2/lib/devise/mapping.rb:46:in
# `find_scope!'
     # /Users/username/.rvm/gems/ruby-2.6.6/gems/devise-4.7.2/lib/devise/mailers/helpers.rb:23:in
     # `initialize_from_record'
     # /Users/username/.rvm/gems/ruby-2.6.6/gems/devise-4.7.2/lib/devise/mailers/helpers.rb:18:in
     # `devise_mail'
     # /Users/username/.rvm/gems/ruby-2.6.6/gems/devise-4.7.2/app/mailers/devise/mailer.rb:9:in
     # `confirmation_instructions'
     # /Users/username/.rvm/gems/ruby-2.6.6/gems/devise-4.7.2/lib/devise/models/authenticatable.rb:200:in
     # `send_devise_notification'
     # /Users/username/.rvm/gems/ruby-2.6.6/gems/devise-4.7.2/lib/devise/models/confirmable.rb:121:in
     # `send_confirmation_instructions'
     # /Users/username/.rvm/gems/ruby-2.6.6/gems/devise-4.7.2/lib/devise/models/confirmable.rb:183:in
     # `send_on_create_confirmation_instructions'
     # ./spec/models/user_spec.rb:125:in `block (4 levels) in <top (required)>''`

Deu um pouco de trabalho encontrar essa causa, já que a maioria dos relatos são para projetos completos e não para gems...
Mas uma vez encontrada, a solução foi bem simples ;]

A solução

No rails_helper.rb adicionei as configurações para o Devise não enviar e-mail no ambiente de teste e isso faz com que , não chamar o Devise::Mapping

RSpec.configure do |config|
...
  Devise::Mailer.delivery_method = :test
  Devise::Mailer.perform_deliveries = false
...
end

Na spec que eu precisava testar esse novo comportamento, apenas adicionei um mock para o método que envia o email:

...
allow_any_instance_of(described_class)
  .to receive(:send_confirmation_instructions)
...

TL; DR

O Devise chama o disparo de e-mail apenas quando o confirmed_at é do momento corrente (Time.current e suas variações)
Inicialmente, antes de encontrar a configuração do rails_helper, havia alterado o confirmed_at { 1.day.ago } para confirmed_at { 1.day.ago } e havia resolvido, daí a descoberta do momento de disparo do e-mail =]

Não confie em mim , leia a doc :)
DOC Confirmable
DOC Devise::Mapping

Top comments (1)

Collapse
 
joathan profile image
Joathan Francisco

Muito obrigado, me ajudou! 👍🏿