访问Rails策略对象中的参数

时间:2018-07-19 20:09:51

标签: ruby-on-rails ruby

更新

我已经尝试__为:specific_trainees添加另一个sql查询,但是这样做并在两个SQL查询上调用UNION只会与所有学员共享资源,无论我是否选择:all_trainees:specific_trainees

我很好奇是否可以在Rails PolicyObject中访问params对象。

下面,我在策略中有一个作用域类

class ResourcePolicy < ApplicationPolicy
  def index?
    true
  end

  alias :new? :index?
  alias :create? :index?

  def destroy?
    record.resource_duty == user
  end

  class Scope < ApplicationPolicy::Scope
    def resolve
      employee_resources = scope.left_outer_joins(:resource_roles, :resource_locations).where(
        '
          resource_duty_id IN(?)
          AND (permitted_employees = ? OR resource_roles.job_role_id IN(?))
          AND (permitted_locations = ? OR resource_locations.location_id IN(?))
        ',
        user.organization_ids,
        Resource.permitted_employees[:all_employees], user.job_role_ids,
        Resource.permitted_locations[:all_locations], user.location_ids
      ).where(namespace: 'company')

      all_trainees_resources = scope.left_outer_joins(:resource_courses).where(
        'resource_duty_id IN(?) AND (permitted_trainees = ? OR resource_courses.course_id IN(?))',
        user.training_organization_ids,
        Resource.permitted_trainees[:all_trainees],
        user.cards.pluck(:course_id)
      ).where(namespace: 'training_provider')

      specific_trainees_resources = scope.left_outer_joins(:resource_courses).where(
        'resource_duty_id IN(?) AND (permitted_trainees = ? OR resource_courses.course_id IN(?))',
        user.training_organization_ids,
        Resource.permitted_trainees[:specific_trainees],
        user.cards.pluck(:course_id)
      ).where(namespace: 'training_provider')

      cardholder_resources = scope.where(resource_duty: user)

      # NOTE: this is all a bit hackey. It might be worth using the sequel gem to improve this
      sql = Resource.connection.unprepared_statement {
        "((#{employee_resources.to_sql}) UNION (#{all_trainees_resources.to_sql}) UNION (#{specific_trainees_resources.to_sql}) UNION (#{cardholder_resources.to_sql})) AS resources"
      }

      Resource.from(sql)
    end
  end
end

我想根据传递的参数将 Resource.permitted_trainees[:all_trainees] 更改为 Resource.permitted_trainees[:specific_trainees]

谢谢!

1 个答案:

答案 0 :(得分:1)

我假设当您说“ Rails PolicyObject”时,是指“ Pundit Policy”,而不是您正在使用的本地解决方案。

也就是说,有可能,尽管Pundit团队不建议这样做。

请参见this section of the docs,该指南实质上建议您执行以下操作:

class UserContext
  attr_reader :user, :show_all_trainees

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

class ApplicationController
  include Pundit

  def pundit_user
    UserContext.new(current_user, request.show_all_trainees)
  end
end

对于您的问题而言,更直接的答案是,我认为更好的方法不是传递参数,而是使用顺序应该已经拥有的User对象或Trainee策略确定要显示哪些受训者。

您可以执行以下操作:

trainee_resources = scope.left_outer_joins(:resource_courses).where(
    'resource_duty_id IN(?) AND (permitted_trainees = ? OR resource_courses.course_id IN(?))',
    user.training_organization_ids,
    policy_scope(Trainee),
    user.cards.pluck(:course_id)
  ).where(namespace: 'training_provider')

您还可以根据类似if角色或其他属性的变量定义,对变量定义进行简单的User声明,以表明他们应该访问哪些受训者。

没有关于您的应用程序体系结构的更多信息,很难过于具体,但是希望其中一种方法可以引导您找到所需的解决方案!