我正在使用Rails 3.2.13和Devise 3.2.4。用户注册后,将生成确认链接:
localhost:3000/users/confirmation?confirmation_token=HpPHitLtV3CnLy2z1ZmQ
我想在确认链接上单击后重定向到mentors/new
操作,但是在确认后,它重定向到我不需要的/users/sign_in
。
到目前为止,这是我的代码:
路线:
devise_for :users
devise_for :users, :controllers => { :confirmations => 'confirmations' }
创建的确认控制器,并从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
在ConfirmationsController中,也许我必须添加一些额外的代码。
在应用程序控制器中,我有以下代码,成功登录后,我将其带到mentor/student
家:
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
结束
def after_sign_up_path_for(resource_or_scope)
root_path
end
通常,逻辑是这样的,但是我不明白如何用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
结束
# 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
现在您已覆盖Devise的after_confirmation_path
方法:
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
这很好,Devise将重定向到您的new_mentor_path
,但在Mentor控制器内部,您将有一个before
文件管理器来检查身份验证,例如:
before_action :authenticate_user! #this will check if your user is signed in or not and if not it'll redirect you
因此,如@Rich Peck所建议,您基本上还需要覆盖show
操作,以便您的用户在重定向到您的new_mentor_path
之前已登录。
在show
操作中,您可以执行以下操作来确保您的用户已登录:
# 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
此外,我在您的after_confirmation_path
中注意到您有
redirect_to new_mentor_path("account_id")
您为什么在路径中将account_id
作为字符串传递?
如果您的account_id
是整数,则必须先在show
操作中设置它,然后像[]那样调用after_confirmation_path
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource, account_id) }
此外,您还必须更改after_confirmation_path
的定义,例如:
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
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
我注释了devise_for :users
,因为每次单击确认链接时都会调用此路由,并且不会调用确认控制器并重定向到登录路径。这是我面临的问题的主要解决方案:
# devise_for :users
devise_for :users, :controllers => { :confirmations => 'confirmations' }