рельсы строят ассоциации от has_many до has_many, поднимают ошибку - PullRequest
0 голосов
/ 18 мая 2018

У меня очень особые случаи.Я понимаю, что дизайн БД не очень хорош, но я не могу это изменить.

class Employer < ApplicationRecord
  has_many :contract_employers
  has_many :contracts, through: :contract_employers
  has_many :crm_contacts, through: :contract_employers

# typical join table, with key: contract_id and employer_id
class ContractEmployer < ApplicationRecord
  belongs_to :contract
  belongs_to :employer
  has_many :crm_contacts

# CrmContact table has key: contract_employer_id
class CrmContact < ApplicationRecord
  belongs_to :contract_employer
  has_one :employer, through: :contract_employer

Учитывая

employer = Employer.create 

У меня нет проблем с запуском

employer.contracts.create

Однако, если я попытаюсь запустить

employer.crm_contacts.create

Это вызовет ошибку

ActiveRecord :: HasManyThroughCantAssociateThroughHasOneOrManyReflection: Невозможно изменить ассоциацию «Employer # crm_contacts», поскольку исходный класс отражения «CrmContact»связан с 'ContractEmployer' через: has_many.

Я проверил исходный код рельсов, в основном он очень четко говорит

    # Construct attributes for :through pointing to owner and associate. This is used by the
    # methods which create and delete records on the association.
    #
    # We only support indirectly modifying through associations which have a belongs_to source.
    # This is the "has_many :tags, through: :taggings" situation, where the join model
    # typically has a belongs_to on both side. In other words, associations which could also
    # be represented as has_and_belongs_to_many associations.
    #
    # We do not support creating/deleting records on the association where the source has
    # some other type, because this opens up a whole can of worms, and in basically any
    # situation it is more natural for the user to just create or modify their join records
    # directly as required.

Так что только типичная таблица соединенияподдерживает model.associations.create?Любое предложение для моего пользовательского случая?

Возьмите, к примеру, мой случай, даже рельс готов выполнить эту работу.Как employer.crm_contacts.create создать запись в средней таблице ContractEmployer?Да, он знает employer.id, но не имеет понятия, что такое contract.id, верно?

1 Ответ

0 голосов
/ 18 мая 2018

Rails не может создать запись средней таблицы в этом случае, но вы можете.

И я полностью согласен с этим (комментарии в исходном коде rails /activerecord/lib/active_record/associations/through_association.rb):

практически в любой ситуации для пользователя более естественно просто создавать или изменять своиприсоединяйтесь к записям напрямую по мере необходимости

Я не вижу здесь проблемы.

class Employer < ApplicationRecord
  # ...

  def create_crm_contact
    ActiveRecord::Base.transaction do
      contract = contracts.create  # will create both `contract` and associated `contract_employer`

      # find the `contract_employer` that has been just created
      contract_employer = contract_employers.find_by(contract_id: contract.id)

      contract_employer.crm_contacts.create
    end
  end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...