Let's imagine that I have a CPA tracking system.
I would have following models: an Offer, it has some Landings, each of them has multiple Links, each of the links has a bunch of Visits.
So, I what I want is DRY code, therefore offer_id
column within visits table is unacceptable. The workaround here is delegated methods like this:
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
It works nice with a single visit, eg visit.offer.id
. But what if I need different visits associated with one offer?
The issue is that I'm unable to construct a valid query using ActiveRecord API. It might look like Visits.where(offer: Offer.first)
, but it doesn't work this way, saying ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: visits.offer: SELECT "visits".* FROM "visits" WHERE "visits"."offer" = 1
, which is predictable.
Question: How should I organize my code to make statements like Visits.where(offer: Offer.first)
work efficiently without duplicating offer_id
column within visits table?
You code was organized nicely, don't need to refactor I think. You can achieve that by defining a scope in Visit
like this:
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
So the query will be:
Visit.from_offer(Offer.first)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.