I have three activerecord models: Customer, Visit and Campaign.
Customer has_many :visits
Visit belongs_to :customer
Campaign has_many :visits
The Visit model tracks everytime a particular customer visits a website, pages visited, ads displayed and most importantly if they made a purchase. A Campaign is a series of Ads the customers see during there visits to the site. Each Campaign lasts 1 hour (24 campaigns a day) and has many visits.
What I'm trying to do is develop some activerecord scopes or class methods that will enable me to identify "Next Visit Purchases".
For example, on July 4th the fourth campaign of the day had 100 visits by customers. I want to be able to look at the next visit for each of those customers and identify those visits/customers that had/made a purchase on that next visit. What I'm finding difficult to wrap my mind around is that customers subsequent visits aren't all on the same day, yet I want to identify the "Next Visit" and those that resulted in a Purchase.
What I envisioned is something like:
Campaign.find(2232).next_visit.purchase #where next_visit and purchase are scopes
or
Visit.find(5445).next_visit.purchase
I have a purchase flag in the visits model so the purchase scope is fairly straight forward.
scope, :purchase, where(:purchase_flag => true)
Also based on the Railscast #215, if I create this scope on the visits model I can then use joins and merge to apply them to the Customer and Campaign models.
Campaign.joins(:visits).merge(Visit.purchase)
Is this the correct approach? If so, how do I define my Next scope and if not, what would you suggest as an alternative approach.
Update: I've gotten some great responses. Just curious to know if the general consensus is that Deepak's approach is on point or are the other responses preferable.
So what you want is to measure the efficiency of a campaign, and have data about the customers that came back after the campaign and did purchases.
I propose:
class Campaign
def next_visits
# Wrapping the whole code of this method in @next_visits will perform local caching
# There is a good railscast that explain it in details (5 minutes long video)
# You can see it there: http://railscasts.com/episodes/1-caching-with-instance-variables
@next_visits ||= begin
# This will be the starting date of "next visits"
since = self.end_of_campaign # I assume you can get the TimeDate of the end of campain
# List of ids of customers that participated to the campaign
customers_ids = self.visits.uniq(:customer_id).pluck(:customer_id)
# Return the visit records
next_visits = Visit.where(purchase_flag: true, customer_id: customers_ids)
next_visits.where('created_at > ?', since).first
end
end
end
Then you call Campaign.find(123).next_visits
EDIT
You should use correct TZ with the variable since
About @next_visits ||= begin ... end
: This is a caching technique. First time you call the method, all the code inside the begin
blok will be executed, and the result (the records) will be stored in the instance variable @next_visits and returned to the caller.
Next time you call the method, the cached result stroed in @next_visits will be directly returned without hitting your database. That is good for performance.
More info about that http://railscasts.com/episodes/1-caching-with-instance-variables