2014-10-08 22 views
2

我有SubscriptionArticle之间的has_many关系,文章有Product如何使用活动记录方法获取相关收藏(代理收藏)

class Subscription < ActiveRecord::Base 
    has_many :articles 
end 

class Article < ActiveRecord::Base 
    belongs_to :subscription 
    belongs_to :product 
end 

class Product < ActiveRecord::Base 
    has_many :subscriptions 
end 

现在。我想简单地从我的订阅中提取所有产品。

解决方案includes

class Subscription < ActiveRecord::Base 
    has_many :articles 
    def products 
    articles.includes(:product).map{|a| ap.product} # Or .map(&:product) 
    end 
end 

解决方案has_many :through

class Subscription < ActiveRecord::Base 
    has_many :articles 
    has_many :products, through: articles 
end 

首先有它不返回,可以在(例如subscription.products.pluck(:id))被链接的集合的缺点,而是一个简单的阵列。

第二个不完全是'语义上'正确的:我不希望它成为一个全面的关联,而只是帮助获取列表。

我是否简单地忽略了一些activerecord方法,它允许我获取相关联的项目?

+0

你能澄清为什么你不希望这是“has_many通过”?从外部看来这是理想的解决方案。 – rossta 2014-10-11 15:24:35

+0

'bar has_many:foo,through::baz'不仅仅是让我获取'self.baz.foo':它为我的公共接口添加了很多方法和东西。而且,它向外界传达了自我,foo和酒吧之间的联系。更糟糕的是,这是一个抽象的抽象:突然我的酒吧知道'baz'和'foo'是如何耦合的。而在干净的面向对象中,我根本就不会对它感兴趣:只是因为我把'foo'发送给了我的'baz';而已。 – berkes 2014-10-14 19:29:35

+0

啊,是的,这都是事实。引用乔尔的话说,“所有不平凡的抽象在某种程度上都是漏洞”。 ActiveRecord既方便又妥协。一般来说,我们可以花时间与框架的约定作斗争,并且更加努力地在所提供的内容之外强制执行其他约定,或者我们可以轻松做到这一点。在某些情况下,我发现许多这些担忧并不重要,但这就是所有的角度。 – rossta 2014-10-15 05:40:56

回答

2

我通常会把它写成“has_many through”,所以返回的products将表现得像一个关系。为了实现在Subscription方法类似的东西,你可以在缺少has_many协会添加到Product和合并上Product预订中加入:

class Product < ActiveRecord::Base 
    has_many :articles 
end 

class Subscription < ActiveRecord::Base 
    has_many :articles 

    def products 
    Product.joins(:articles).merge(articles) 
    end 
end 

在这种情况下,Subscription#products将返回ActiveRecord集合。

+0

我想这里是关键:“将缺少的has_many关联添加到'Product'” – moonfly 2014-10-12 18:19:13

+0

我不完全确定'Product'中'has_many:articles'的真正含义。这听起来像它被用作私人帮手,以允许创建更好的连接;但实际上我正在向产品的公共API添加东西。或者我错过了一个关键点? – berkes 2014-10-15 13:00:41

+1

如果没有上下文,我不知道'Product'的'has_many:articles'对你的域名真正意义。在最基本的层面上,它仅仅反映了'Article''belongs_to''产品的反例。你是对的,它确实增加了产品的公共API,其中包括像我所展示的那样进行连接的能力。否则,您需要在您的产品方法中下拉到SQL,或者将您自己的关系保持为私有。为了获得通过Rails提供的便利,产品确实需要“了解”文章。 – rossta 2014-10-15 16:25:21