область действия has_many с проверкой состояния вложенной ассоциации - PullRequest
1 голос
/ 19 октября 2019

У меня есть модель учетной записи, которая имеет много проектов, и модель проекта, которая имеет много требований. Одна учетная запись действует как учетная запись библиотеки, а другие учетные записи являются учетными записями пользователей.

Таблица требований имеетexternal_id, который является строковым идентификатором, который используется для корреляции с внешней базой данных и является уникальным в контексте учетной записи. Но требования в учетной записи библиотеки и учетной записи пользователя могут использовать один и тот же external_id (т. Е. «REQ-23»), поэтому он не является уникальным ключом в таблице требований.

Существует таблица RelatedRequirement,сопоставляет связанные требования.

Ниже я хочу получить связанные требования, относящиеся к учетной записи пользователя, выполнив проверку account_id в моей области действия has_many.

Сторона базы данных:

account
  id

project
  id
  account_id

requirement
  id
  project_id
  external_id

related_requirements
   external_id
   related_external_id

Сторона модели:

class RelatedRequirement < ActiveRecord::Base
  belongs_to :requirement,,
    foreign_key: :external_id,
    class_name: "Requirement",
    primary_key: :external_id

  belongs_to :related_requirement,
    foreign_key: :related_external_id,
    class_name: "Requirement",
    primary_key: :external_id
end

class Requirement < ActiveRecord::Base
 belongs_to :project
  has_one :account, through: :project

  has_many :related_requirement_mappings,
    foreign_key: :external_id,
    class_name: "RelatedRequirement",
    primary_key: :external_id

  has_many :related_requirements,
    # === this works ===
    #-> { joins(:project).where(projects: {account_id: 2 }) },
    # === this doesn't work ===
    -> { joins(:project).where(projects: {account_id: project.account_id }) },
    through: :related_requirement_mappings, 
    foreign_key: :related_external_id, 
    class_name: "Requirement",
    primary_key: :external_id

Мои вопросы:

  1. Mainвопрос, я хотел бы иметь возможность получить related_requirements в той же учетной записи, используя has_many: related_requirements выше, но я не могу добраться до связанной account_id в моей области,
>req = Requirement.find(1)
>req.related_requirements  

  Requirement Load (81.3ms)  SELECT "requirements".* FROM "requirements"
NameError (undefined local variable or method `project' for #<Requirement::ActiveRecord_Relation:0x00007fe3f0b1ac20>)

ЧтоОднако в настоящее время я могу сделать следующее:

class Requirement < ActiveRecord::Base

has_many :related_requirements,
    #-> { joins(:project).where(prjects: {account_id: project.account_id }) },
    through: :related_requirement_mappings, 
    foreign_key: :related_external_id, 
    class_name: "Requirement",
    primary_key: :external_id

scope :for_account, -> (account) { joins(:project).where(projects: {account_id: account.id}) }
>req = Requirement.find(1)
>req.related_requirements.for_account(req.account)

Это выглядит немного глупо, поскольку похоже, что я вызываю метод экземпляра в req, и я должен иметь возможность доступа к учетной записи req изнутри. related_requirements,без определения этой дополнительной области действия for_account.

Поскольку external_id не является уникальным полем, требование own_to в таблице RelatedRequirement фактически может соответствовать нескольким требованиям, но оно просто возвращает одно. В идеале я хотел бы добавить условие области (основанное на клонированном другом поле базы данных), которое указывает, что это из учетной записи библиотеки. Однако, если я сделаю это, то вышеупомянутый запрос related_requirements будет прерван, поскольку условие области будет включено в запрос и больше не будет возвращать related_requirements учетной записи пользователя, меня это интересует. Я не уверен относительно того, почему условие, которое я указываю в области RelatedRequirement, каким-то образом применяется в областях, которые я определяю для требования, когда я не вызываю его явно.
class RelatedRequirement < ActiveRecord::Base
  belongs_to :requirement,
    -> { where cloned: nil },
    foreign_key: :external_id,
    class_name: "Requirement",
    primary_key: :external_id

  belongs_to :related_requirement,
    -> { where cloned: nil },
    foreign_key: :related_external_id,
    class_name: "Requirement",
    primary_key: :external_id


class Requirement < ActiveRecord::Base
  belongs_to :project
  has_one :account, through: :project

  has_many :related_requirement_mappings,
    foreign_key: :external_id,
    class_name: "RelatedRequirement",
    primary_key: :external_id

  has_many :related_requirements,
    # -> { joins(:project).where(projects: {account_id: project.account_id }) },
    through: :related_requirement_mappings, 
    foreign_key: :related_external_id, 
    class_name: "Requirement",
    primary_key: :external_id

  scope :for_account, -> (account) { joins(:project).where(projects: {account_id: account.id}) }

irb(main):060:0> r.related_requirements.to_sql
=> "SELECT \"requirements\".* FROM \"requirements\" INNER JOIN \"related_requirements\" ON \"requirements\".\"external_id\" = \"related_requirements\".\"related_external_id\" WHERE \"related_requirements\".\"external_id\" = 'REQ-1' AND \"requirements\".\"cloned\" IS NULL"

irb(main):061:0> r.related_requirements.for_account(r.account)
=> #<ActiveRecord::AssociationRelation []>

1 Ответ

0 голосов
/ 24 октября 2019

Я нашел ответ на свой вопрос, отправив сообщение для будущей ссылки.

Если я определю область действия в моих отношениях has_many с аргументом, то этот аргумент будет объектом self, но мне не нуженвызвать has_many с этим аргументом. Это было бы неявно передано.

has_many :related_requirements,
    (requirement) -> { joins(:project).where(projects: {account_id: requirement.account_id }) },
    through: :related_requirement_mappings, 
    foreign_key: :related_external_id, 
    class_name: "Requirement",
    primary_key: :external_id

Тогда я смогу получить связанные требования, ограниченные условием принадлежности к учетной записи (которая является вложенной ассоциацией):

irb(main):028:0> r.related_requirements.to_sql
  Account Load (6.0ms)  SELECT  "accounts".* FROM "accounts" INNER JOIN "projects" ON "accounts"."id" = "projects"."account_id" WHERE "projects"."id" = $1 LIMIT 1  [["id", 9]]
=> "SELECT \"requirements\".* FROM \"requirements\" INNER JOIN \"projects\" ON \"projects\".\"id\" = \"requirements\".\"project_id\" INNER JOIN \"related_requirements\" ON \"requirements\".\"external_id\" = \"related_requirements\".\"related_external_id\" WHERE \"related_requirements\".\"external_id\" = 'REQ-1' AND \"projects\".\"account_id\" = 2"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...