假设我有一个CPA跟踪系统。
我会有以下模型:一个报价,它有一些着陆,每个着陆都有多个链接,每个链接都有一堆访问。
所以,我想要的是 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
.但是,如果我需要一个优惠相关的不同访问怎么办?
问题是我无法使用活动记录 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
列?
你的代码组织得很好,我认为不需要重构。您可以通过在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)