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)
Muito obrigado, me ajudou! 👍🏿