Here’s the scoop;
I had a need to send emails to users at a specific interval in a time period based on two simple conditions:
- Is it the right day?
- Does this user want emails? (Did they opt out yet?)
I elected to run a cron every day at a specific time (using the whenever gem). When it runs, the date is compared to
is_nag_time. If true, every user is looped through checking the latter condition. Let’s get to some code
def get_date_diff # Get the difference in weeks or months if self.weekly? return (Date.today.cweek - self.start_date.cweek).weeks elsif self.monthly? return (Date.today.year - self.start_date.year) * 12 + Date.today.month - self.start_date.month - (Date.today.day >= self.start_date.day ? 0 : 1).months end end def current_survey_date return self.start_date + (self.get_date_diff - 1).days end def is_nag_time return self.current_survey_date + (Date.today.end_of_month.day * 0.75).round.days end def current_survey return self.surveys.find_by_position(self.get_date_diff.to_i) end # Determine the current iteration date (current_step_date) # Add Time percentage to it based on the iteration (weekly or monthly) def self.do_the_nag if program.is_nag_time == Date.today time_to_nag = Time.now counter = 1 # Loop through users program.users .where(:email_opt_in => true) .each do |user| if counter > 50 counter = 1 time_to_nag = time_to_nag + 1.minute end NagMailer.delay(:run_at => time_to_nag).next_survey_reminder(user, program) end end end # schedule.rb every 1.day, :at => '10am' do runner 'Program.do_the_nag' end
I think the code is fairly straight forward. I choose to run it on a daily basis, instead of just scheduling the emails in the future, because the dates may change at any given time. I believe this accomidates for most, if not all, situations.