Rails中的重定向循环

时间:2019-03-31 01:40:09

标签: ruby-on-rails devise

我的用户通过提供emailaccount_typepassword在根URL上注册。他们收到一封电子邮件,要求确认。他们确认电子邮件后就可以登录。但是在他们可以使用任何网站功能之前,我希望他们通过提供username并设置一个Stripe帐户来完成其个人资料。我最初的想法是在before_action中以ApplicationController的身份进行此操作。就像这样:

class ApplicationController < ActionController::Base
 before_action :current_user_has_complete_profile_and_stripe_account

 private
 def current_user_has_complete_profile_and_stripe_account
  if user_signed_in? && current_user.username.blank?
    redirect_to users_onboard_path
  end
 end  
end

但是,当我以新批准的用户身份登录时,这会导致重定向循环。终端输出为:

Redirected to http://localhost:3000/users/onboard
Filter chain halted as :current_user_has_complete_profile_and_stripe_account rendered or redirected

为什么要转到该页面然后又重定向到该页面?

3 个答案:

答案 0 :(得分:2)

该方法似乎是正确的。但是,如果原始请求指向users_onboard_path,则使用当前方法将导致重定向循环。
为了避免循环,当原始请求定向到current_user_has_complete_profile_and_stripe_account操作时,您需要跳过users/onboard before_action调用。为此,您可以在控制器类内部的顶部users_controller.rb的下面添加以下行(假设该文件包含onboard操作):

skip_before_action :current_user_has_complete_profile_and_stripe_account, only: [:onboard]

这样做,我们基本上会跳过current_user_has_complete_profile_and_stripe_account操作执行之前调用的onboard操作,因此删除循环。

更新:

我将借助自己创建的测试应用来说明这一点:

应用程序的application_controller.rb文件如下:

class ApplicationController < ActionController::Base
  before_action :current_user_has_complete_profile_and_stripe_account

  private

  def current_user_has_complete_profile_and_stripe_account
    p "I'm in the before_action call current_user_has_complete_profile_and_stripe_account"
    if some_condition?
      p "I'm redirecting to the onboard API"
      redirect_to onboard_users_path
    end
  end

  def some_condition?
    true
  end
end

在此文件中,我们定义了一个before_action回调以重定向到入门路径。

此应用的users_controller.rb文件如下:

class UsersController < ApplicationController
  def login
    p "I'm in login"
    render json: { message: "This is a message from login action" }
  end

  def onboard
    p "I'm in onboard!"
    render json: { message: "This is a message from onboard action" }
  end
end

当我尝试使用登录API时,我遇到了重定向循环,如终端输出所示:

Started GET "/users/login" for ::1 at 2019-04-10 11:16:09 +0530
Processing by UsersController#login as */*
"I'm in the before_action call current_user_has_complete_profile_and_stripe_account"
"I'm redirecting to the onboard API"
Redirected to http://localhost:3001/users/onboard
Filter chain halted as :current_user_has_complete_profile_and_stripe_account rendered or redirected
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)


Started GET "/users/onboard" for ::1 at 2019-04-10 11:16:09 +0530
Processing by UsersController#onboard as */*
"I'm in the before_action call current_user_has_complete_profile_and_stripe_account"
"I'm redirecting to the onboard API"
Redirected to http://localhost:3001/users/onboard
Filter chain halted as :current_user_has_complete_profile_and_stripe_account rendered or redirected
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)

基本上,我们在调用中点击了before_action方法以首先登录,然后尝试重定向到onboard_users_path。但是,在重定向中调用/users/onboard时,我们再次点击了before_action块,这再次尝试将我们重定向到/users/onboard,这成为一个循环。
但是,如果将skip_before_action :current_user_has_complete_profile_and_stripe_account, only: [:onboard]添加到users_controller.rb中,则会得到以下输出:

Started GET "/users/login" for ::1 at 2019-04-10 11:22:34 +0530
Processing by UsersController#login as */*
"I'm in the before_action call current_user_has_complete_profile_and_stripe_account"
"I'm redirecting to the onboard API"
Redirected to http://localhost:3001/users/onboard
Filter chain halted as :current_user_has_complete_profile_and_stripe_account rendered or redirected
Completed 302 Found in 3ms (ActiveRecord: 0.0ms)


Started GET "/users/onboard" for ::1 at 2019-04-10 11:22:34 +0530
Processing by UsersController#onboard as */*
"I'm in onboard!"
Completed 200 OK in 1ms (Views: 0.3ms | ActiveRecord: 0.0ms)

从日志中可以看到,登录调用重定向到板载,但是这里before_action重定向被跳过了,我们得到了期望的响应。
同样,在您的示例中,第一个调用将重定向到onboard,随后的调用也将继续重定向,因为before_action回调也将执行onboard动作!

答案 1 :(得分:1)

该方法是完全有效的。 您只需检查当前的控制器和操作:如果它们已经在users_onboard_path上,则无需再次重定向。

答案 2 :(得分:1)

您的应用程序重定向,因为在您登录时,条件users_signed_in? && current_user.username.blank?仍然为真。因此会触发相同的回调,因为您的所有控制器都继承自ApplicationController,并且最终导致重定向循环。

您可以在回调中添加一个检查,以确认您还没有加入

return if request.path =~ /onboard/

另一种解决方案是让您所有与入职有关的控制器操作都跳过回调

skip_before_action :current_user_has_complete_profile_and_stripe_account, only: [:onboard]