Rails 4:是否可以从控制器中提取复杂的认证逻辑?

时间:2015-04-15 01:43:44

标签: authentication ruby-on-rails-4 controller service-object

传统Rails最佳实践旨在减少控制器中的逻辑代码,因为它们被设计为路由而不执行复杂的任务。

但是,如果您有半复杂的身份验证逻辑,那么如何从控制器中合理地提取该逻辑呢?

在我看来,对于任何基本应用来说,这都是相当“标准”的逻辑。虽然逻辑直接与“路由”有关,但似乎我将逻辑放入控制器并且它不是很小......我在这里过度杀戮了吗?

是否可以轻松地将此逻辑提取到单独的类中,因为redirect_to ...方法只能在控制器中访问?

class SessionsController < ApplicationController
  # Login page POSTs here to perform authentication logic
  def create
    user = User.find_by(email: params[:email])
    if user and user.authenticate(params[:password]) # default has_secure_password
      if user.confirmed?
        if user.account.active?
          flash[:notice] = "Successfully logged in"
          redirect_to root_path
        else
          flash[:error] = "This account is no longer active"
          redirect_to inactive_account_path(user.account)
        end
      else
        flash[:alert] = "You are not confirmed yet"
        redirect_to confirmation_path(user.confirmation_token)
      end
    else
      flash[:error] = "Invalid email or password"
      redirect_to login_path
    end
  end
end

1 个答案:

答案 0 :(得分:1)

如果您愿意,可以将所有内容扔进回调或类似内容,以便方法更简单,但路由应该或多或少属于控制器。

class SessionsController < ApplicationController
  before_filter :set_user, :check_confirmed

  def create
    if user.account.active?
      flash[:notice] = 'Successfully logged in'
      redirect_to root_path
    else
      flash[:error] = 'This account is no longer active'
      redirect_to inactive_account_path(user.account)
    end
  end

  private

  def set_user
    user = User.find_by(email: params[:email])
    return if user.authenticate(params[:password])
    flash[:error] = 'Invalid email or password'
    redirect_to login_path
  end

  def check_confirmed
    return if user.confirmed?
    flash[:alert] = 'You are not confirmed yet'
    redirect_to confirmation_path(user.confirmation_token)
  end
end

请注意,如果您希望ApplicationController本身稍微瘦一点,可以将回调放在SessionsController中。

但是请记住,这是会话控制器,用户状态应该在其他地方进行管理。理想情况下,从逻辑位置,您的create方法应如下所示:

def create
  user = User.find_by(email: params[:email])
  if user
    flash[:notice] = 'Successfully logged in'
    redirect_to root_path
  else
    flash[:error] = 'Invalid email or password'
    redirect_to login_path
  end
end

并将用户状态回调或类似内容置于其他位置(ApplicationController或whatevs)。