Rails中具有相同类的多个关联的最佳实践? [英] Best practices for multiple associations with the same class in Rails?
问题描述
我认为我的问题最好被描述为一个例子。假设我有一个名为事物的简单模型,它具有一些简单数据类型的属性。像...
I think my question is best described as an example. Let's say I have a simple model called "Thing" and it has a few attributes that are simple data types. Something like...
Thing
- foo:string
- goo:string
- bar:int
这并不难。 db表将包含具有这三个属性的三列,我可以使用@ thing.foo或@ thing.bar之类的东西来访问它们。
That isn't hard. The db table will contain three columns with those three attributes and I can access them with something like @thing.foo or @thing.bar.
但是问题是试图解决的是,当 foo或 goo不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是带有不同数据的 Whazit实例。所以现在事情看起来像这样……
But the problem I'm trying to solve is what happens when "foo" or "goo" can no longer be contained in a simple data type? Assume that foo and goo represent the same type of object. That is, they are both instances of "Whazit" just with different data. So now Thing might look like this...
Thing
- bar:int
但是现在有一个名为 Whazit的新模型,看起来像这样...
But now there is a new model called "Whazit" that looks like this...
Whazit
- content:string
- value:int
- thing_id:int
到目前为止,一切都很好。现在这是我遇到的问题。如果我有@thing,该如何设置它以按名称引用我的2个Whazit实例(根据记录,业务规则是,任何Thing都将始终恰好具有2个Whazits)?也就是说,我需要知道我拥有的Whazit基本上是foo还是goo。显然,在当前设置中我无法执行@ thing.foo,但是我很理想。
So far this is all good. Now here is where I'm stuck. If I have @thing, how can I set it up to refer to my 2 instances of Whazit by name (For the record, the "business rule" is that any Thing will always have exactly 2 Whazits)? That is, I need to know if the Whazit I have is basically foo or goo. Obviously, I can't do @thing.foo in the current setup, but I'd that is ideal.
我最初的想法是添加名称属性到Whazit,以便我可以获取与我的@thing相关的Whatzits,然后以这种方式选择我想要的Whazit。
My initial thought is to add a "name" attribute to Whazit so I can get the Whatzits associated with my @thing and then choose the Whazit I want by name that way. That seems ugly though.
有更好的方法吗?
推荐答案
您可以通过以下两种方法进行操作。首先,您可以建立两个 belongs_to
/ has_one
关系:
There are a couple of ways you could do this. First, you could set up two belongs_to
/has_one
relationships:
things
- bar:int
- foo_id:int
- goo_id:int
whazits
- content:string
- value:int
class Thing < ActiveRecord::Base
belongs_to :foo, :class_name => "whazit"
belongs_to :goo, :class_name => "whazit"
end
class Whazit < ActiveRecord::Base
has_one :foo_owner, class_name => "thing", foreign_key => "foo_id"
has_one :goo_owner, class_name => "thing", foreign_key => "goo_id"
# Perhaps some before save logic to make sure that either foo_owner
# or goo_owner are non-nil, but not both.
end
另一种选择是更清洁,但在交易时更痛苦与插件等,是单表继承。在这种情况下,您有Foo和Goo这两个类,但它们都保存在whazits表中,并带有区分它们的类型列。
Another option which is a little cleaner, but also more of a pain when dealing with plugins, etc., is single-table inheritance. In this case you have two classes, Foo and Goo, but they're both kept in the whazits table with a type column that distinguishes them.
things
- bar:int
whazits
- content:string
- value:int
- thing_id:int
- type:string
class Thing < ActiveRecord::Base
belongs_to :foo
belongs_to :goo
end
class Whazit < ActiveRecord::Base
# .. whatever methods they have in common ..
end
class Foo < Whazit
has_one :thing
end
class Goo < Whazit
has_one :thing
end
在两种情况下,您都可以做类似 @ thing.foo
和 @ thing.goo
。使用第一种方法,您需要执行以下操作:
In both cases you can do things like @thing.foo
and @thing.goo
. With the first method, you'd need to do things like:
@thing.foo = Whazit.new
而使用第二种方法,您可以执行以下操作:
whereas with the second method you can do things like:
@thing.foo = Foo.new
STI具有但是,如果您使用的是旧版插件和gem,则可能会遇到一系列问题。通常,当他们真正想要的是 @ object.base_class
时,调用 @ object.class
的代码就会出现问题。必要时打补丁很容易。
STI has its own set of problems, though, especially if you're using older plugins and gems. Usually it's an issue with the code calling @object.class
when what they really want is @object.base_class
. It's easy enough to patch when necessary.
这篇关于Rails中具有相同类的多个关联的最佳实践?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!