siv rj
siv rj

Reputation: 1511

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

Upvotes: 3

Views: 4579

Answers (2)

Mandeep
Mandeep

Reputation: 9173

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 

Upvotes: 2

siv rj
siv rj

Reputation: 1511

After research, I am posting the correct answer for the question:

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)  #This will detect if user is logged in.

  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

protected
def after_confirmation_path_for(resource_name, resource)

  if resource.is_a?(User)
   new_mentor_path("account_id") #do not provide redirect_to which is already taken in respond_with_navigational(resource)
  else
   root_path
  end
 end  
end

I commented out devise_for :users, because this route was being called every time when clicking on the confirmation link and the confirmation controller was not being called and redirecting to the sign-in path. This is the main solution for the issue I faced:

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

Upvotes: 0

Related Questions