Полиморфная ассоциация и ссылка на внешний ключ могут ссылаться на одну и ту же таблицу. Как создать новый объект?

Упрощенный пример того, что у меня есть,

class Apple < ActiveRecord::Base
 has_many :bananas, as: :bananable, dependent: destroy
 has_many :bananas
end
class Orange < ActiveRecord::Base
 has_many :bananas, as: :bananable, dependent: destroy
end
class Banana < ActiveRecord::Base
 belongs_to :bananable, polymorphic: true
 belongs_to :apple
end

Таким образом, банан может принадлежать либо Apple, либо Orange как банабельный, но будет принадлежать Apple через внешнее ключевое отношение независимо. Это может показаться немного вынужденным в контексте фруктов, но фактические модели довольно сложны, поэтому я упростил ситуацию. В основном полиморфная ассоциация определяет область, в которой существует Banana, но Banana является частью Apple независимо от его области.

Проблема, с которой я столкнулась, - это когда я пытаюсь создать новый банан. Например:

@Apple.bananas.new(valid_params)

Этот параметр устанавливает столбец внешнего ключа apple_id в таблице бананов, но не устанавливает столбцы полиморфной ассоциации (bananable_id и bananable_type). Единственный способ, которым я нашел установить оба: создать новый банан, как указано выше, а затем вручную установить столбцы полиморфной ассоциации перед сохранением.

Есть ли лучший способ сделать это?

Возможно, что-то вроде:

@banana = @Apple.bananas.new(valid_params)
@Apple.bananables << @banana

или для апельсинов

@banana = @Apple.bananas.new(valid_params)
@Orange.bananables << @banana

Лучшее, что я придумал до сих пор, это

@banana = @Apple.bananas.new(valid_params)
if params.has_key?(:orange_id)
 @banana.bananable = @orange
else
 @banana.bananable = @apple
end
@banana.save
2 ответа

Вы можете попробовать использовать атрибут: inverse_of в вашей модели Banana. Я знаю, что в документах Rails говорится, что это не имеет никакого эффекта, но похоже, что это что-то помогло в моем предыдущем коде. Вы можете попробовать, хотя я не гарантирую.

belongs_to :bananable, polymorphic: true, inverse_of: :bananas

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

В качестве еще одного варианта убедитесь, что проверки не прерывают обновления базы данных. Для тестирования мне пришлось использовать save! чтобы были исключены исключения, и я мог поймать, где скрытые проблемы нарушают мои ассоциации.


Прежде всего, ясно понять полиморфную ассоциацию. Ruby on Rails Guide содержит "with polymorphic associations, a model can belong to more than one other model, on a single association".

Я уверен, что вам не нужны две ассоциации с одной и той же таблицей. Всякий раз, когда вы создаете banana через apple, bananable_id и bananable_type не будут установлены, потому что рельсы найдут связь через apple_id и не беспокоятся о каких-либо других ассоциациях.

Насколько я знаю, вы излишне усложняете свои модели. Бьюсь об заклад, нижняя ассоциация может получить все необходимые вам функции.

class Apple < ActiveRecord::Base
 has_many :bananas, as: :bananable, dependent: destroy
end
class Orange < ActiveRecord::Base
 has_many :bananas, as: :bananable, dependent: destroy
end
class Banana < ActiveRecord::Base
 belongs_to :bananable, polymorphic: true
end

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

licensed under cc by-sa 3.0 with attribution.