Search code examples
ruby-on-railsrubydeviseconfirmation

How to redirect to some other page after user confirmed


I am using Rails 3.2.13 and Devise 3.2.4. After user registration, the confirmation link is generated:

localhost:3000/users/confirmation?confirmation_token=HpPHitLtV3CnLy2z1ZmQ

I want to redirect to the mentors/new action after clickin on the confirmation link, but after confirmation it redirects to /users/sign_in which I don't want.

This is my code so far:

Routes:

devise_for :users
devise_for :users, :controllers => { :confirmations => 'confirmations' }

Created Confirmations controller and overrides from Devise::ConfirmationsController:

class ConfirmationsController < Devise::ConfirmationsController
  protected

def after_confirmation_path_for(resource_name, resource)
  if resource.has_role? :user
    redirect_to new_mentor_path("account_id")
  else
    root_path
  end
end
end

In ConfirmationsController, maybe I have to add some extra code.

In application controller I have this code which takes me to the mentor/student home after a successfull sign-in:

def after_sign_in_path_for(resource_or_scope)
if resource_or_scope.is_a?(User)
  if current_user.user_type == "mentor"
    home_mentors_path(:account_id => current_user.account_id)
  else
    home_students_path(:account_id => current_user.account_id)
  end
end

end

def after_sign_up_path_for(resource_or_scope)
  root_path
end

Generally the logic is like this, but I do not understand how to do this with Devise:

def activate
  @user = User.where("activation_code = ?","#{params[:id]}").first
  if [email protected]?
   if @user.created_at < 24.hours.ago
     if @user and @user.activate
      cookies[:user_id][email protected]
      if @user.user_type == "student"
        redirect_to new_student_path
      else
        redirect_to new_mentor_path
      end
    else
      @user.destroy
      redirect_to "/"
    end
  else
    @user.destroy
    redirect_to "/"
  end
else
  redirect_to "/"
end

end


Solution

  • If you look at the Devise GitHub repository, this method is called when you click on the confirmation link:

    # GET /resource/confirmation?confirmation_token=abcdef
    def show
      self.resource = resource_class.confirm_by_token(params[:confirmation_token])
      yield resource if block_given?
    
      if resource.errors.empty?
        set_flash_message(:notice, :confirmed) if is_flashing_format?
        respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
      else
        respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
      end
    end
    

    Now you have overriden Devise's after_confirmation_path method:

    protected
    def after_confirmation_path_for(resource_name, resource)
      if resource.has_role? :user
        redirect_to new_mentor_path("account_id")
      else
        root_path
      end
    end
    

    which is fine and Devise will redirect to your new_mentor_path but inside your Mentor controller you would have a before filer to check for authentication, something like:

    before_action :authenticate_user! #this will check if your user is signed in or not and if not it'll redirect you
    

    So as @Rich Peck suggested, you basically need to override your show action also so that your user is signed in before being redirected to your new_mentor_path.

    In your show action you can do something like this to make sure your user is signed in:

    # GET /resource/confirmation?confirmation_token=abcdef
    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)
        respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
      else
        respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render :new }
      end
    end
    

    Also, I noticed in your after_confirmation_path you have

    redirect_to new_mentor_path("account_id")
    

    Why are you passing account_id as a string in your path?

    If your account_id is an integer then you'll have to first set it inside the show action and then call your after_confirmation_path like

    respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource, account_id) }
    

    Also you'll have to change the definition of after_confirmation_path like:

    def after_confirmation_path_for(resource_name, resource, account_id)
      if resource.has_role? :user
        redirect_to new_mentor_path(account_id)
      else
        root_path
      end
    end