【问题标题】:Using a pundit policy to restrict scope of objects of another class使用权威政策来限制另一类对象的范围
【发布时间】:2017-10-10 18:59:25
【问题描述】:

我有一个名为 dispatch 的模型,它是一个连接表,它与其他两个模型(转诊请求和临床医生)相关联。在我的应用程序中,员工用户将创建一个转诊请求记录,其中包含有关他们的患者正在寻找的一些详细信息。一些未构建的逻辑将找到与患者记录中所述的至少一种保险相匹配的所有临床医生用户,这将导致向这些临床医生中的每一个发送邮件。调度模型是我尝试记录转诊请求和临床医生之间关系的方式,因此我知道哪些临床医生收到了电子邮件,也因此我可以记录他们的回复(是或否)。

临床医生也属于市场,工作人员属于大学,属于市场。

每个临床医生都有一个临床医生资料,除了 clincian_profiles 表之外,还有一个 clinician_profiles_insurances 表,因此我可以调用 .clinician_profile.insurances 给作为临床医生的给定用户并返回他们所购买的所有保险。

对于给定的转诊请求,我还可以调用 .insurances 来显示患者拥有的所有保险。

我正在尝试在 dispatch new 方法中使用 Pundit 策略范围来执行以下操作:

-仅显示与员工用户所在大学处于同一市场的临床医生用户。

-仅显示至少有一种与推荐请求匹配的保险的临床医生用户。

这是迄今为止我最好的滑动,它甚至不能用于限制市场范围。我做错了什么?

调度政策

    class DispatchPolicy < ApplicationPolicy
  class Scope
    attr_reader :user, :scope

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

    def resolve

      if user.admin?
        scope.all
      else
        scope.joins(:clinician).merge(User.where(market: user.market))
      end
    end
  end

我的用户有多个角色:

enum role: { staff: 0, clinician: 1, admin: 2 }

以下是关系:

class Dispatch < ApplicationRecord
    belongs_to :referral_request
    belongs_to :clinician, class_name: 'User', foreign_key: 'user_id'

class ReferralRequest < ApplicationRecord
  belongs_to :user, -> { where role: :staff }
  has_many :dispatches
  has_many :clinicians, through: :dispatches

module StaffUser
  extend ActiveSupport::Concern

  included do
    belongs_to :university
    has_many :patients
    has_many :referral_requests
    validates :university_id, presence: true, if: :staff?
  end

这是我在 Dispatches 控制器中的新方法:

def new
@clinicians = policy_scope(Dispatch)
@dispatch = @referral_request.dispatches.new
end

这是 dispatches/new.html.erb 中的表格,我试图在其中显示所有用户

1) 是临床医生 2) 与员工用户所在大学属于同一市场 3) 在他们的临床医生资料中至少有一种与转诊请求相关的保险相匹配的保险。

<% @clinicians.each do |clinician| %>
  <tr>
    <td><%= clinican.id %></td>
    <td><%= clinican.name %></td>
    <td><%= clinican.market.name %></td>
    <td><%= clinican.clinician_profile.insurances.map(&:name).to_sentence %></td>
    <td><%= clinican.clinician_profile.genders.map(&:name).to_sentence %></td>
    <td><%= clinican.clinician_profile.races.map(&:name).to_sentence %></td>
    <td><%= clinican.clinician_profile.languages.map(&:name).to_sentence %></td>
  </tr>
<% end %>
</tbody>
</table>

保险模式:

class Insurance < ApplicationRecord
    has_and_belongs_to_many :patients
    has_and_belongs_to_many :clinician_profiles
    has_and_belongs_to_many :markets
end

患者模型

class Patient < ApplicationRecord
  belongs_to :author, -> { where role: :staff }, class_name: 'User', foreign_key: 'user_id'

  has_and_belongs_to_many :genders
  has_and_belongs_to_many :concerns
  has_and_belongs_to_many :insurances
  has_and_belongs_to_many :races
  has_many :referral_requests
  belongs_to :staff_doctor, class_name: 'User', foreign_key: 'staff_doctor_id'

  def has_referral?
    !self.referral_requests.empty?
  end
end

**Clinician concern**
require 'active_support/concern'

module ClinicianUser
  extend ActiveSupport::Concern

  included do
    has_one :clinician_profile
    has_many :lists
    has_many :universities, through: :lists
    has_many :dispatches
    has_many :referral_requests, through: :dispatches
    after_create :create_clinician_profile
    belongs_to :market
    validates :market_id, presence: true, if: :clinician?
  end

  class_methods do
  end
end

员工关注

require 'active_support/concern'

module StaffUser
  extend ActiveSupport::Concern

  included do
    belongs_to :university
    has_many :patients
    has_many :referral_requests
    validates :university_id, presence: true, if: :staff?
  end

  class_methods do
  end
end

临床医师档案模型

class ClinicianProfile < ApplicationRecord
  belongs_to :user, -> { where role: :clinician }
  has_and_belongs_to_many :languages
  has_and_belongs_to_many :races
  has_and_belongs_to_many :insurances
  has_and_belongs_to_many :genders
end

我的想法是否正确?对于我正在尝试做的全部或部分工作,权威政策是一个很好的解决方案吗?感谢所有反馈。我显然有点迷路了。

【问题讨论】:

    标签: ruby-on-rails pundit


    【解决方案1】:

    为什么不一次解决一个问题?

    暂时忽略 Pundit 并提出一个 ActiveRecord 查询来返回您所期望的。

    user = User.where(role: :staff).first
    Dispatch.joins(:clinician).merge(User.where(market: user.market))
    

    这加入了“临床医生”.. 由于模型中的“类:用户”,我认为这实际上是幕后的“用户”表。 对于第 1 部分和第 2 部分,此查询似乎很好。

    运行 AR 查询时,应首先将所有调度与用户连接起来,并仅选择与传递给策略的“当前用户”具有相同“市场”的调度。

    但请记住:

    @clinicians = policy_scope(Dispatch)
    

    返回的是调度,而不是“临床医生”(用户),所以在您编写的代码中,“临床医生.id”将是您不想要的调度表 ID?除非我弄错了。

    如果第 1 部分和第 2 部分还没有工作,请先尝试使其工作。

    第 3 部分“在他们的临床医生资料中至少有一种与转诊请求相关的保险相匹配的保险。”

    听起来您还必须加入“推荐请求”,并执行更多 SQL,我只是不知道您的保险是如何计算出来的 域(是 has_many :insurance_plans 等,需要更多信息)

    【讨论】:

    • 感谢您提供有用的反馈。当我按照您的建议分配用户然后在控制台中运行第二行时,它运行但返回空。 user.market 返回波士顿,即 id:2。我在分贝中有属于波士顿的临床医生。我可能会误解,但在我看来,您编写的查询搜索并返回调度,但我认为我想要返回的是临床医生列表。我很可能会遗漏一些东西,所以请告诉我你的想法。
    • 我为保险等添加了额外的模型,所以你可以看到它们。
    猜你喜欢
    • 1970-01-01
    • 2015-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多