How to migrate/update to Devise 3.1

Reading Time: 2 minutes

Recently we updated our online retrospective tool from Rails 3 to Rails 4.

We got some issues related to the Devise gem, so I'm going to share with you what we did to fix those issues with Devise 3.1.

In this current version of Devise more secure defaults have been included, more info about that here:

http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/

One of the common issues that arise when you update to the latest version is that confirmation emails don't work, to fix this issue you will have to update the Devise mailers using an extra param.

The following includes both versions of the code, what you see before updating and what you get after updating:
<p>Thank you for registering....</p>
<p>
  Please click on the link below to confirm that this email account belongs to you.<br>
-(before)<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>
+(after)<%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @token) %>
</p>

<p>
  If the link above doesn't work, you can copy the following URL and paste it in your browser:<br>
-(before)<%= confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>
+(after)<%= confirmation_url(@resource, :confirmation_token => @token) %>
 </p>

  <p>This email will self-destruct in 1 day!</p>

If you want to sign in automatically after confirming your email you need to paste this in your config/initializers/devise.rb file (this is only recommended as a temporary solution):

 config.allow_insecure_sign_in_after_confirmation = true

If you are already using Cucumber for testing then you can use it to test your email confirmation as well.

When /^I confirm my email$/ do
   # after updating Devise 3.1 version the token generator is now encrypted
   # and we need to generate a new token to be able to confirm the email successfully
   token_email, token = Devise.token_generator.generate(User, :confirmation_token)
   User.last.update_attributes(confirmation_token: token)
   step 'I wait "1" seconds'
   visit root_path + "users/confirmation?confirmation_token=#{token_email}"
end

In the following code we are assuming the user is the Devise model.
The content belongs to the app/models/user.rb file

We have to remove

:token_authenticatable

From

devise :omniauthable, :trackable, :token_authenticatable,

Don't forget adding the callback which generates the user's authentication_token:

 before_save :ensure_authentication_token

The method's content is:

 def ensure_authentication_token
   if authentication_token.blank?
     self.authentication_token = generate_authentication_token
   end
 end    

private

def generate_authentication_token
   loop do
      token = Devise.friendly_token
      break token unless User.where(authentication_token: token).first
   end
end

For auth validation add this content in the app/controllers/application_controller.rb file:

  # callback
  before_filter :authenticate_user_from_token!

 # The method's content:
  def authenticate_user_from_token!
    user_email = params[:user_email].presence
    user       = user_email && User.find_by_email(user_email)

    if user && Devise.secure_compare(user.authentication_token, params[:user_token])
      # if you want to validate in every request add sign_in user, store: false
      sign_in user
    end
  end

Now, you might get the following warning message:

"DEPRECATION WARNING: devise :token_authenticatable is deprecated. Please check Devise 3.1 release notes for more information on how to upgrade"

If you have followed the instructions until this point, then you can get rid of that message by refreshing your browser or running your test suite. Congratulations, you are now using more secure defaults with the Devise gem 🙂

See you around

H.

0 Shares:
You May Also Like