如何使用多态类模拟 has_many :through
我明白为什么 ActiveRecord 不能支持多态类上的 has_many :through
。但我想模仿它的一些功能。考虑以下情况,其中连接表关联两个多态类:
class HostPest < ActiveRecord::Base
belongs_to :host, :polymorphic => true
belongs_to :pest, :polymorphic => true
end
class Host < ActiveRecord::Base
self.abstract_class = true
has_many :host_pests, :as => :host
end
class Pest < ActiveRecord::Base
self.abstract_class = true
has_one :host_pest, :as => :pest
end
class Dog < Host ; end
class Cat < Host ; end
class Flea < Pest ; end
class Tick < Pest ; end
目标
因为我无法执行 has_many :pests, :through=>:host_pests, :as=>:host
(等) ,我想模拟这四种方法:
dog.pests (returns a list of pests associated with this dog)
flea.host (return the host associated with this flea)
cat.pests << Tick.create (creates a HostPest record)
tick.host = Cat.create (creates a HostPest record)
问题 1
我已经有了前两种方法(pests
和 host
)的工作实现,但想要知道这是否是最好的方法(具体来说,我是否忽略了 ActiveRecord 关联中的一些有帮助的内容):
class Host < ActiveRecord::Base
def pests
HostPest.where(:host_id => self.id, :host_type => self.class).map {|hp| hp.pest}
end
end
class Pest < ActiveRecord::Base
def host
HostPest.where(:pest_id => self.id, :pest_type => self.class).first.host
end
end
问题 2
我对如何实现 <<
和 =< 感到困惑/code> 这里隐含的方法:
cat.pests << Tick.create # => HostPest(:host=>cat, :pest=>tick).create
tick.host = Cat.create # => HostPest(:host=>cat, :pest=>tick).create
有什么建议吗? (再说一遍,ActiveRecord 关联可以提供任何帮助吗?)
I understand why ActiveRecord can't support has_many :through
on polymorphic classes. But I would like to emulate some of its functionality. Consider the following, where a join table associates two polymorphic classes:
class HostPest < ActiveRecord::Base
belongs_to :host, :polymorphic => true
belongs_to :pest, :polymorphic => true
end
class Host < ActiveRecord::Base
self.abstract_class = true
has_many :host_pests, :as => :host
end
class Pest < ActiveRecord::Base
self.abstract_class = true
has_one :host_pest, :as => :pest
end
class Dog < Host ; end
class Cat < Host ; end
class Flea < Pest ; end
class Tick < Pest ; end
The goal
Since I can't do has_many :pests, :through=>:host_pests, :as=>:host
(etc), I'd like to emulate these four methods:
dog.pests (returns a list of pests associated with this dog)
flea.host (return the host associated with this flea)
cat.pests << Tick.create (creates a HostPest record)
tick.host = Cat.create (creates a HostPest record)
Question 1
I've got a working implementation for the first two methods (pests
and host
), but want to know if this is the best way (specifically, am I overlooking something in ActiveRecord associations that would help):
class Host < ActiveRecord::Base
def pests
HostPest.where(:host_id => self.id, :host_type => self.class).map {|hp| hp.pest}
end
end
class Pest < ActiveRecord::Base
def host
HostPest.where(:pest_id => self.id, :pest_type => self.class).first.host
end
end
Question 2
I'm stumped on how to implement the <<
and =
methods implied here:
cat.pests << Tick.create # => HostPest(:host=>cat, :pest=>tick).create
tick.host = Cat.create # => HostPest(:host=>cat, :pest=>tick).create
Any suggestions? (And again, can ActiveRecord associations provide any help?)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在
Pest
类上实现host=
方法非常简单。我们需要确保在设置新主机时清除旧主机(因为 AR 不会从中间表中清除旧值)。在
Host
类上实现pests<<
方法有点复杂。在Host
类上添加pests
方法以返回害虫的聚合列表。在pests
方法返回的对象上添加<<
方法。现在
Implementing the
host=
method on thePest
class is straight forward. We need to make sure we clear the old host while setting a new host (as AR doesn't clear the old value from the intermediary table.).Implementing
pests<<
method onHost
class is bit more involved. Add thepests
method on theHost
class to return the aggregated list of pests. Add the<<
method on the object returned bypests
method.Now
您可以通过使用 STI 和常规关联来解决您的问题:
将所有主机存储在名为
hosts
的表中。将名为type
的字符串列添加到表中。继承
Host
类来创建新的主机。将所有害虫存储在名为
pests
的表中。将名为type
的字符串列添加到表中。继承
Pest
类来创建新的害虫。现在,您可以运行以下命令:
注意
Rails 支持 多态类上的
has_many :through
。您需要指定source_type
才能使其工作。考虑标记模型:
假设产品和公司可以被标记。
我们可以在 Tag 模型上添加关联来获取所有标记的产品,如下所示:
You can address your problem by using STI and regular association:
Store all the hosts in a table called
hosts
. Add a string column calledtype
to the table.Inherit the
Host
class to create new hosts.Store all the pests in a table called
pests
. Add a string column calledtype
to the table.Inherit the
Pest
class to create new pests.Now when you can run following commands:
Note
Rails supports
has_many :through
on polymorphic classes. You need to specify thesource_type
for this to work.Consider the models for tagging:
Let's say products and companies can be tagged.
We can add an association on Tag model to get all the tagged products as follows: