chhhris
chhhris

Reputation: 375

Devise Confirmable behavior when user clicks "confirmation" link more than once

I'm using Devise confirmable. I'm having an issue whereby if the user clicks on the confirmation link more than once (i.e. if the user forgot they already confirmed or whatever) they get a nasty error:

NoMethodError at /confirmation
undefined method `new_user_registration_path' for  <ActionDispatch::Routing::RoutesProxy:0x007fe739a40510>

This is the confirmation link:

<%= link_to 'Confirm my account', confirmation_url(@user, host: @host, confirmation_token: @user.confirmation_token) %>

Ideal behavior would flash[:alert] = "You've already confirmed" + a redirect to login page.

I tried creating my own confirmations_controller.rb and messing with the routes, but did not have any success.

Thanks in advance for any assistance!

Upvotes: 3

Views: 2240

Answers (2)

Mark Schneider
Mark Schneider

Reputation: 380

By default Devise treats a user's repeated arrival at the confirmation page (with the same confirmation_token) as an error condition. I think the easiest way to avoid the message is to override the pending_any_confirmation method in Devise::Models::Confirmable. Removing from that method the lines which flag it as an error condition should do the trick.

Assuming you have a User model, in your app/models/user.rb file, insert this:

private

def pending_any_confirmation
  if (!confirmed? || pending_reconfirmation?)
    yield
# else
#   self.errors.add(:email, :already_confirmed)
#   false
end

Note: I'm showing the commented lines so you can see what exactly in Devise's original method is being changed. Your method instead might have just a single line: yield if (!confirmed? || pending_reconfirmation?)

Upvotes: 3

chhhris
chhhris

Reputation: 375

Solved it on my own after finding an almost identical question on SO: How redirect 'Confirmation token invalid' on Devise

Copying the confirmations_controller.rb from devise wholesale into my app didn't work, but calling super for create et al. and then specifying a new show action worked.

class ConfirmationsController  < Devise::ConfirmationsController

  def show
    self.resource = resource_class.confirm_by_token(params[:confirmation_token])

    if resource.errors.empty?
      set_flash_message(:notice, :confirmed) if is_navigational_format?
      sign_in(resource_name, resource)
      respond_with_navigational(resource){ redirect_to
            after_confirmation_path_for(resource_name, resource) }
    else
      flash[:notice] = "Your account is already confirmed. Please login."
      redirect_to '/login'
    end
  end

end

Upvotes: 1

Related Questions