真的很像"has many through"。
Item:
has_many :item_available_addons
has_many :item_addons, through: :item_available_addons
ItemAddon:
has_many :item_available_addons
has_many :items, through: :item_available_addons
ItemAvailableAddon:
belongs_to :item
belongs_to :item_addon
我对看起来相似的型号名称有点困惑,但结构应该是这个或类似的。
如果“可用性事实”只是一个链接并且不需要额外数据(例如,插件与项目的关系类型:例如,如果需要这种插件,请考虑使用 has_and_belongs_to_many或可选)。否则,你很乐意这样做。
has_and_belongs_to_many
工作更简单,并且不是那么可定制。 但是设置它会更容易,因为它不需要维护额外的模型。不过,仍然需要一张额外的桌子。您根本不需要ItemAvailableAddon 模型。所以:
Item
has_and_belongs_to_many :item_addons
ItemAddon
has_and_belongs_to_many :items
现在是棘手的部分。连接表。还不赶紧迁移,先阅读完整答案:
rails g migration CreateItemAddonsItems item:references item_addon:references
这将为您提供一个简单的迁移您需要编辑as specified here:
class CreateItemAddonsItems < ActiveRecord::Migration
def change
create_table :item_addons_items, id: false do |t|
t.references :item
t.references :item_addon
end
end
end
注意事项:
- 我不太明白 Rails 如何确定默认连接表名称背后的逻辑(他们说这是词法顺序,但是...),但试验总是有效的:在指定关联后不要进行任何迁移:fire启动 Rails 控制台并尝试使用该关联(类似
Item.first.item_addons 的简单明了的东西):它会告诉您哪个表不存在:创建它。这就是我确定迁移名称的方式。
- 如果上面描述的 trial&error 看起来很尴尬,您可以手动指定连接表的名称。您不必拘泥于 Rails 的猜测。
- 链接说使用
t.integer :<model>_id,但它与t.references :<model> 相同,这是一个约定。我更喜欢使用后者,因为它更具语义(它是一个整数,但它可以作为参考:并非每个整数都是参考)。
-
id: false 在表创建中。这很重要。
- 我见过有人在每个字段后添加
null: false。如果正确使用关联,我怀疑这应该有任何影响。因为否则任何事情都可能发生。
- 没有
ItemAddonItem 模型或类似的东西。这就是has_and_belongs_to_many 的全部意义所在。一个简单的连接表,除了维护关联之外没有其他用途。
就是这样。迁移,你应该一切准备就绪。只有一件事:如果ItemAddon 只是Addon,事情看起来会简单得多。反正是有关联的。