I'm trying to chain some scoping methods (instead of using an actual scope), but I have a problem combining them. I now have the code below working, but it's not completely DRY. It would be way nicer if I could write something like
Project.from_advertisers(advertiser_ids).active
and
Project.from_advertisers(advertiser_ids).finished
instead of having to use the separate methods 'active_from_advertisers' and 'finished_from_advertisers' I created, as you can see in my code below. These separate methods work, but the preferred chained methods like above give me the error that the first is an array...
Is it possible to accomplish this some way inside the model?
Thanks for any help!
#### campaign.rb
# datetime :start_on
# datetime :end_on
# integer :advertiser_id
class Campaign < ActiveRecord::Base
belongs_to :project
belongs_to :advertiser
def self.active
self.select{|c| c.end_on >= Time.now && c.start_on <= Time.now }
end
def self.finished
self.select{|c| c.end_on <= Time.now }
end
end
#### project.rb
class Project < ActiveRecord::Base
has_many :campaigns
def self.active
includes(:campaigns).joins(:campaigns).select{|p| p.end_on >= Time.now && p.start_on <= Time.now }
end
def self.finished
includes(:campaigns).joins(:campaigns).select{|p| p.end_on && p.end_on <= Time.now }
end
def self.from_advertisers(advertiser_ids)
includes(:campaigns).joins(:campaigns).select{|p| advertiser_ids.include?(p.advertiser_id)}
end
def self.active_from_advertisers(advertiser_ids)
includes(:campaigns).select{|p| advertiser_ids.include?(p.advertiser_id) && p.end_on >= Time.now && p.start_on <= Time.now }
end
def self.finished_from_advertisers(advertiser_ids)
includes(:campaigns).select{|p| advertiser_ids.include?(p.advertiser_id) && p.end_on && p.end_on <= Time.now }
end
def advertiser_id
campaigns.first.try(:advertiser_id)
end
def start_on
campaigns.map(&:start_on).min
end
def end_on
campaigns.map(&:end_on).max
end
end
Using .select
will always return an array.
You might consider changing your queries using the where
method.
def self.active
where("end_on >= #{Time.now} && start_on <= #{Time.now}")
end