pundit_user:未定义的方法`current_user&#39;对于#<user:0x007fcefbc2b150>

时间:2015-11-26 08:43:04

标签: ruby-on-rails ruby ruby-on-rails-4 devise pundit

我有两个布局AdminDomain。我不需要在Admin布局中进行任何额外配置。但如果用户尝试访问Domain布局,则他们必须位于有效域中。

这意味着,我需要自定义我的所有Domain政策,以同时包含current_usercurrent_domain。我发现可以使用UserContextpundit_user完成此操作...所以这就是我所做的:

application_controller.rb

class ApplicationController < ActionController::Base
  include Pundit
  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  def pundit_user
    UserContext.new(current_user, current_domain)
  end

  def after_sign_out_path_for(resource)
    root_path
  end

  def current_domain
    @current_domain ||= Domain.where(name: requested_domain).first
  end
  helper_method :current_domain

private

  def requested_domain
    return request.env["SERVER_NAME"]
  end

  def user_not_authorized
    # reset_session
    flash[:alert] = "You are not authorized to perform this action"
    redirect_to(request.referrer || root_path)
  end
end

请注意,当我访问Admin布局时,current_domain将为nil,如果我访问Domain布局的任何路由,则current_domain将设置为当前访问域

user_context.rb

class UserContext
  attr_reader :current_user, :current_domain

  def initialize(current_user, current_domain)
    @current_user = current_user
    @current_domain = current_domain
  end
end

问题

假设我有这个政策:

user_policy.rb

class UserPolicy < ApplicationPolicy
  attr_reader :user, :scope

  def initialize(user, scope)
    @user = user
    @scope = scope
  end

  def index?
    binding.pry # debugging
    current_user.admin? ||
    current_user.domain == current_domain
  end

private

  def current_user
    # return user.is_a?(User) ? user : user.current_user
    user.current_user
  end

  def current_domain
    # return user.is_a?(User) ? nil : user.current_domain
    user.current_domain
  end

end

当应用程序运行current_user时,必须根据文档(https://github.com/elabs/pundit#additional-context)在UserPolicy中提供current_domain

但我得到了

undefined method `current_user' for #<User:0x007fcefbc2b150>

这意味着,我仍然有用户对象,而不是user.current_useruser.current_domain

如果您需要进一步说明,请告诉我。我在这里缺少什么?

1 个答案:

答案 0 :(得分:0)

这是我自己的愚蠢错误。

<强> 问题

我在before_filter中拨打domain/base_controller.rb电话:

class Domain::BaseController < ApplicationController
  before_action :authenticate_user!
  before_action :domain_exists?
  before_action :verify_domain!

private

  def verify_domain!
    # PROBLEM: this line was updating pundit_user again to user object
    raise Pundit::NotAuthorizedError unless DomainConsolePolicy.new(current_user, current_domain).authorized?
  end

  def domain_exists?
    if current_domain.blank?
      redirect_to root_path, alert: 'Domain that you provided is not valid or is permanently removed!'
    end
  end
end

解决方案:

我已使用headless政策,因为现在current_user

current_domainpundit_user都设有application_controller

domain/base_controller.rb

class Domain::BaseController < ApplicationController
  before_action :authenticate_user!
  before_action :domain_exists?
  before_action :verify_domain!

private

  def verify_domain!
    # SOLUTION
    authorize :domain_console, :has_access?
  end

  def domain_exists?
    if current_domain.blank?
      redirect_to root_path, alert: 'Domain that you provided is not valid or is permanently removed!'
    end
  end
end

policy/domain_console_policy.rb

class DomainConsolePolicy < Struct.new(:user, :domain_console)

  def has_access?
    user.current_user.admin? ||
    user.current_user.domain_id == user.current_domain.id
  end

end

由于