has_many : сквозная ассоциация с обратным добавлена ​​​​дважды

Я создал пример приложения, которое освещает мою проблему.

По сути, у меня есть ассоциация «многие ко многим» с классом STI:

class Basket < ActiveRecord::Base
  has_many :basket_fruits, inverse_of: :basket
  has_many :fruits, through: :basket_fruits

  has_many :apples, through: :basket_fruits, source: :fruit, class_name: 'Apple'
  has_many :oranges, through: :basket_fruits, source: :fruit, class_name: 'Orange'
  has_many :bananas, through: :basket_fruits, source: :fruit, class_name: 'Banana'
end

class BasketFruit < ActiveRecord::Base
  belongs_to :basket, inverse_of: :basket_fruits
  belongs_to :fruit, inverse_of: :basket_fruits

  validates :basket, :fruit, presence: true
end

class Fruit < ActiveRecord::Base
  has_many :basket_fruits, inverse_of: :fruit
  has_many :baskets, through: :basket_fruits

  validates :type, presence: true, inclusion: ['Apple', 'Banana', 'Orange']

  validates :baskets, presence: true
end

class Apple < Fruit; end
class Banana < Fruit; end
class Orange < Fruit; end

Схема:

Basket(id: integer, created_at: datetime, updated_at: date time)
BasketFruit(id: integer, fruit_id: integer, basket_id: integer, created_at: datetime, updated_at: date time)
Fruit(id: integer, type: string, created_at: datetime, updated_at: datetime)

Когда новый Banana создается с помощью ActiveAdmin, он использует код, эквивалентный следующему:

Basket.create
banana = Basket.first.bananas.build(basket_ids: [Basket.first.id])

Проблема в том, что этот код создает две ассоциации, которые можно наблюдать даже без сохранения Банана:

banana.basket_fruits.size
=> 2

Почему это происходит и как это исправить?

Обновить

Только что обнаружил это. Может быть, поэтому AR пытается добавить отношения дважды, вместо того, чтобы «переопределить», как я ожидал:

banana = Basket.first.bananas.build
=> #<Banana id: nil, type: "Banana", created_at: nil, updated_at: nil>

banana.baskets
=> #<ActiveRecord::Associations::CollectionProxy []>

В этом случае нужно было бы предварительно заполнить ассоциацию после вызова #build




Ответы (1)


Почему вы назначаете корзину дважды?

 Basket.first.bananas.build(basket_ids: [Basket.first.id])

Я бы написал это так:

 Basket.first.bananas.build
person Ryan Bigg    schedule 05.03.2014
comment
Валидация мешает мне это сделать. - person ybart; 05.03.2014