我已经构建了以下但没有使用Rails模型。 我有以下模型,没有任何指定的关系。 故事 目的 文化 道德 值 书 关键词 字符
我手动将所有关系信息作为数组存储在单个关系表中,其结构如下所示
我想做的是这样的事情 - 模型: 故事 - > has_many :: tale_relations 目的 - > has_many :: tale_relations 文化 - > has_many :: tale_relations 道德 - > has_many :: tale_relations 值 - > has_many :: tale_relations 书籍 - > has_many :: tale_relations 关键字 - > has_many :: tale_relations 字符 - > has_many :: tale_relations
Model: TaleRelation ->
belongs_to: :tale
belongs_to: :purpose
belongs_to: :culture
belongs_to: :morals
belongs_to: :values
belongs_to: :books
belongs_to: :keywords
belongs_to: :characters
但是不希望tale_relations表为这些不同的模型中的每一个都有多个列 我的意思是我不想要tale_id,purpose_id,moral_id等等(8个这样的专栏) 希望能够通过表名(:for column)和id#(:for_id column)来识别记录。
目前它正在手动工作,但只是认为代码实际上变得干净简单,并且实际上可扩展,如果我可以使这个工作。只有两列可以识别任何关系。
答案 0 :(得分:0)
如果您在模型上施加额外的结构,我怀疑您的问题会变得容易多了。您调用模型TaleRelation这一事实让我认为大多数这些事情应该是直接相关的故事,这可以通过has_and_belongs_to_many关系完成,然后其他事情可能与through: :tale相关。但我认为我们也可以解决上述问题。
首先,您要查看polymorphic associations。在上面发布的代码中,第一步是在TaleRelation中使用@calendar.posts
,在其他模型中使用belongs_to :relatable, polymorphic: true
。这要求tale_relations表有两列relatable_id和relatable_type,这就是你要为for和for_id做的事情。
但是我认为你真的想进一步采取这一步,并摆脱故事,人物,价值观等列。我们可以使用两个多态关系而不仅仅是一个。
首先,表结构(4列):
has_many :tale_relations, as: :relatable
和模型
create_table :tale_relations do |t|
t.integer :relater_id
t.string :relater_type
t.integer :relatee_id
t.string :relatee_type
end
我正在使用回调进行的操作是每次使用给定的关联器创建或销毁TaleRelation并且相关时,它会创建或销毁相应的反转。因此,如果给定的Tale与Character相关,那么Character也与Tale相关。如果你不想要这种对称性,那就把这些回调拿出来。
现在,例如,在故事:
class TaleRelation < ActiveRecord::Base
belongs_to :relater, polymorphic: true
belongs_to :relatee, polymorphic: true
after_create :create_inverse_relationship
after_destroy :destroy_inverse_relationship
def create_inverse_relationship
self.class.find_or_create_by(inverse_attributes)
end
def destroy_inverse_relationship
self.class.find_by(inverse_attributes).try(:destroy)
end
def inverse_attributes
{
relater_id: relatee_id,
relater_type: relatee_type,
relatee_id: relater_id,
relatee_type: relater_type
}
end
end
和“价值与品格”中的类似事物等等。现在是一个故事has_many:字符,无需将它们的ID存储为逗号分隔的字符串或数组,因为它看起来就像你在表格中所做的那样。确保不要包含任何自引用的has_many语句(即不要将class Tale < ActiveRecord::Base
has_many :tale_relations, as: :relater, dependent: :destroy
has_many :characters, through: :tale_relations, source: :relatee, source_type: "Character"
has_many :values, through: :tale_relations, source: :relatee, source_type: "Value"
# and so on
end
放入Character中)
因此我们通过多态relater_id和relater_type定义与TaleRelation的关系,因此我们可以拥有所有这些关系而不需要所有列。通过这种关系,我们可以(多态地)收集正确类的所有相关性。这给了我:
has_many :characters
请注意,这不会传播二阶关系。即,
2.2.2 > t = Tale.create(name: "T")
=> #<Tale id: 1, name: "T">
2.2.2 > c = Character.create(name: "C")
=> #<Character id: 1, name: "C">
2.2.2 > d = Character.create(name: "D")
=> #<Character id: 2, name: "D">
2.2.2 > v = Value.create(name: "V")
=> #<Value id: 1, name: "V">
2.2.2 > t.characters << c
=> #<ActiveRecord::Associations::CollectionProxy [#<Character id: 1, name: "C">]>
2.2.2 > v.characters << c
=> #<ActiveRecord::Associations::CollectionProxy [#<Character id: 1, name: "C">]>
2.2.2 > v.characters << d
=> #<ActiveRecord::Associations::CollectionProxy [#<Character id: 1, name: "C">, #<Character id: 2, name: "D">]>
2.2.2 > d.values
=> #<ActiveRecord::Associations::CollectionProxy [#<Value id: 1, name: "V">]>
2.2.2 > t.characters.first.values
=> #<ActiveRecord::Associations::CollectionProxy [#<Value id: 1, name: "V">]>
即使t有一个带有值的字符。一旦你开始这样做,很快你就会拥有与其他一切相关的一切。