2016-01-20 125 views
0

让我们假设我拥有一个CPA跟踪系统。与Rails的深层模型关联

我会有以下模型:一个优惠,它有一些登陆,他们每个人都有多个链接,每个链接都有一堆访问。

所以,我想要的是DRY代码,所以offer_id列内访问表是不可接受的。此处的解决方法是这样的委托方法:

class Offer < ActiveRecord::Base 
    has_many :landings 
    has_many :links, through: :landings 
    has_many :visits, through: :landings 
end 

class Landing < ActiveRecord::Base 
    belongs_to :offer 
    has_many :links 
    has_many :visits, through: :links 
end 

class Link < ActiveRecord::Base 
    belongs_to :landing 
    has_many :visits 
    delegate :offer, to: :landing 
end 

class Visit < ActiveRecord::Base 
    belongs_to :link 
    delegate :landing, to: :link 
    delegate :offer, to: :link 
end 

它可以在单次访问中很好地工作,例如, visit.offer.id。但是如果我需要与一个报价相关的不同访问呢?

问题是我无法使用ActiveRecord API构造有效的查询。它可能看起来像Visits.where(offer: Offer.first),但它不以这种方式工作,说ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: visits.offer: SELECT "visits".* FROM "visits" WHERE "visits"."offer" = 1,这是可预测的。

问:我应该如何安排我的代码,使像有效Visits.where(offer: Offer.first)工作报表,而不访问表中复制offer_id列?

回答

1

您的代码组织得很好,不需要重构我的想法。您可以通过在Visit这样定义范围内实现这一目标:

class Visit < ActiveRecord::Base 
    scope :from_offer, -> (offer) { 
    joins(link: :landing).where(ladings: {offer_id: offer.id}) 
    } 

    scope :from_landing, -> (landing) { 
    joins(:link).where(links: {landing_id: landing.id}) 
    } 
end 

所以查询将是:

Visit.from_offer(Offer.first) 
+0

谢谢,它的工作原理!你能否提供类似的登陆选择范围('Visit.from_landing(Landing.second)')? –

+0

是的,它是类似的,男人,检查我的更新!查看以下参考资料以获取更多详细信息http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/ClassMethods.html –

+0

很酷,谢谢! –