Jeremy Lynch
Jeremy Lynch

Reputation: 7230

Return devise confirmation token in device 3.1

Now that Devise has removed the :confirmation_token from the database, how can I return the devise confirmation token in rspec?

I am trying to test the confirmable module by manually visiting the user_confirmation path with the confirmation token. How can I achieve this?

Upvotes: 5

Views: 4591

Answers (2)

Mark Berry
Mark Berry

Reputation: 19102

A slight variation on the very helpful answer by Leonardo Pinto:

# Generate new raw/encrypted confirmation token pair and update database.
# This lets us visit the new "raw" path to confirm the user.
raw_confirmation_token, db_confirmation_token = 
  Devise.token_generator.generate(User, :confirmation_token)
User.last.update_attribute(:confirmation_token, db_confirmation_token)
visit user_confirmation_url(confirmation_token: raw_confirmation_token)

Background: As outlined in this Platformatec blog post under "Store digested tokens in the database," Devise 3.1+ sends the user a "raw" confirmation token, and saves an encrypted version in the database. When the user clicks on the raw link, the raw token is re-encrypted before searching in the database. See send_confirmation_instructions and generate_confirmation_token in this source code:

https://github.com/plataformatec/devise/blob/master/lib/devise/models/confirmable.rb

This code generates a new pair of raw and encrypted tokens, updates the last User in the database with the new encrypted version, then visits the raw version. The token should match and the account should be confirmed.

Although not in the original question, I also wanted to test for the correct link in the Devise confirmation mailer, but I don't think that's possible: when I create a user, the confirmation email is sent immediately, so the email's body contains the original raw token, not the new one generated here.

Upvotes: 10

Leonardo Pinto
Leonardo Pinto

Reputation: 129

The confirmation flow has changed. Now, the confirmation flow uses User.confirm_by_token. You can do something like this:

old_token = User.last.confirmation_token
new_token = Devise.token_generator.digest(User, :confirmation_token, old_token)
User.last.update_attribute(:confirmation_token, new_token)
visit user_confirmation_url(confirmation_token: old_token)

Upvotes: 5

Related Questions