методы сборки для has_one, хотя has_one - PullRequest
0 голосов
/ 11 ноября 2018

Рельсы 5.1.2 Рубин 2.5.3

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

has_many настройка

class Subscriber < ApplicationRecord
  has_many :subscriptions, inverse_of: :subscriber
  has_many :promotions, through: :subscriptions, inverse_of: :subscriptions

  accepts_nested_attributes_for :subscriptions
  accepts_nested_attributes_for :promotions
end

class Subscription < ApplicationRecord
  belongs_to :subscriber, inverse_of: :subscriptions
  belongs_to :promotion, inverse_of: :subscriptions
end

class Promotion < ApplicationRecord
  has_many :subscriptions, inverse_of: :promotion
  has_many :subscribers, through: :subscriptions, inverse_of: :subscriptions

  accepts_nested_attributes_for :subscriptions
  accepts_nested_attributes_for :subscribers
end

В приведенной выше модели Subscriber, которая настроена на использование has_many, будут работать следующие отношения:

s = Subscriber.new
s.subscriptions.build
# OR
s.promotions.build

После этого я бы ожидал, что Subscriber будет вести себя так же, как и has_one отношения

has_one настройка

class Subscriber < ApplicationRecord
  has_one :subscription, inverse_of: :subscriber
  has_one :promotion, through: :subscription, inverse_of: :subscriptions

  accepts_nested_attributes_for :subscription
  accepts_nested_attributes_for :promotion
end

class Subscription < ApplicationRecord
  belongs_to :subscriber, inverse_of: :subscription
  belongs_to :promotion, inverse_of: :subscriptions
end

class Promotion < ApplicationRecord
  has_many :subscriptions, inverse_of: :promotion
  has_many :subscribers, through: :subscriptions, inverse_of: :subscription

  accepts_nested_attributes_for :subscriptions
  accepts_nested_attributes_for :subscribers
end

Однако попытка построить вложенную promotion ассоциацию с эквивалентными has_one методами построения приводит к NoMethodError (undefined method 'build_promotion' for #<Subscriber:0x00007f9042cbd7c8>) ошибке

s = Subscriber.new
s.build_promotion

Однако это работает:

s = Subscriber.new
s.build_subscription

Я чувствую, что логично ожидать, что вложенные has_one отношения будут строиться так же, как и has_many.

Это ошибка или по замыслу?

1 Ответ

0 голосов
/ 11 ноября 2018

Проверка кода, когда вы вызываете has_one, он создает методы build_, create_ и create_..! ТОЛЬКО, если отражение "конструируемо"

https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/activerecord/lib/active_record/associations/builder/singular_association.rb#L16

define_constructors(mixin, name) if reflection.constructable?

Теперь, проверяя метод constructable?, он возвращает результат calculate_constructable https://github.com/rails/rails/blob/ed1eda271c7ac82ecb7bd94b6fa1b0093e648a3e/activerecord/lib/active_record/reflection.rb#L452

А для класса HasOne он возвращает false, если вы используете опцию :through https://github.com/rails/rails/blob/ed1eda271c7ac82ecb7bd94b6fa1b0093e648a3e/activerecord/lib/active_record/reflection.rb#L723

def calculate_constructable(macro, options)
  !options[:through]
end

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

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