Использование политики эксперта для ограничения области действия объектов другого класса

У меня есть модель под названием «отправка» с таблицей соединений, которая связывает две другие модели: запросы направления и врачей. В моем приложении штатный пользователь создаст запись запроса направления, в которой будут содержаться некоторые сведения о том, что ищет его пациент. Некоторая незастроенная логика найдет всех пользователей-клиницистов, которые соответствуют хотя бы одной страховке, указанной в истории болезни пациента, и это приведет к отправке почтового сообщения каждому из этих врачей. Модель отправки — это то, как я пытаюсь зафиксировать взаимосвязь между запросами направления и клиницистами, чтобы знать, какие клиницисты получили электронные письма, а также чтобы я мог записывать их ответы (да или нет).

Клиницисты также принадлежат рынкам, а персонал принадлежит университетам, которые принадлежат рынкам.

У каждого врача есть профиль врача, и в дополнение к таблице clincian_profiles есть таблица Clinician_profiles_insurances, так что я могу вызвать .clinician_profile.insurances для данного пользователя, который является врачом, и вернуть все страховки, которые они взяли.

По заданному запросу направления я также могу позвонить в .insurances, чтобы показать все страховки, которые есть у пациента.

Я пытаюсь использовать область политики 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

Я вообще правильно об этом думаю? Является ли политика эксперта хорошим решением для всего или части того, что я пытаюсь сделать? Спасибо за все отзывы. Я явно немного потерялся.


person mike9182    schedule 10.10.2017    source источник


Ответы (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)

возвращает отправки, а не «клиницистов» (пользователей), поэтому в написанном вами коде «clinicians.id» будет идентификатором таблицы отправки, чего вы не хотите? Если я не ошибаюсь.

Попробуйте сначала заставить работать части 1 и 2, если они еще не работают.

Часть 3 «иметь хотя бы одну страховку в своем профиле врача, которая соответствует страховке, связанной с запросом направления».

Похоже, вам придется также присоединиться к «рекомендательным запросам» и сделать больше SQL, я просто не знаю, как вычисляется страхование в вашем домене (это has_many :insurance_plans и т. д., что потребует дополнительной информации)

person jeremy04    schedule 10.10.2017
comment
спасибо за этот полезный отзыв. когда я назначаю пользователя, как вы предлагаете, а затем запускаю вторую строку в консоли, она запускается, но возвращается пустой. user.market возвращает Бостон, который имеет идентификатор: 2. У меня в базе есть клиницисты из Бостона. Я могу ошибаться, но мне кажется, что запрос, который вы написали, ищет и возвращает депеши, но я думаю, что я хочу вернуть список врачей. Я очень хорошо могу что-то упустить, поэтому, пожалуйста, дайте мне знать, что вы думаете. - person mike9182; 11.10.2017
comment
Я добавил дополнительные модели для страховки и т. д., чтобы вы могли их увидеть. - person mike9182; 11.10.2017