module JamRuby
class EmailBatch < ActiveRecord::Base
self.table_name = "email_batches"
has_many :email_batch_sets, :class_name => 'JamRuby::EmailBatchSet'
attr_accessible :from_email, :subject, :test_emails, :body
attr_accessible :lock_version, :opt_in_count, :sent_count, :started_at, :completed_at
default_scope :order => 'created_at DESC'
VAR_FIRST_NAME = '@FIRSTNAME'
VAR_LAST_NAME = '@LASTNAME'
DEFAULT_SENDER = "noreply@jamkazam.com"
BATCH_SIZE = 1000
BODY_TEMPLATE =<
Paragraph 2 ... "#{VAR_FIRST_NAME}" will be replaced by users first name
Thanks for using JamKazam!
FOO include AASM aasm do state :pending, :initial => true state :testing state :tested state :delivering state :delivered state :disabled event :enable do transitions :from => :disabled, :to => :pending end event :reset, :after => :did_reset do transitions :from => [:disabled, :testing, :tested, :delivering, :delivered, :pending], :to => :pending end event :do_test_run, :before => :will_run_tests do transitions :from => [:pending, :tested, :delivered], :to => :testing end event :did_test_run, :after => :ran_tests do transitions :from => :testing, :to => :tested end event :do_batch_run, :before => :will_run_batch do transitions :from => [:tested, :pending, :delivered], :to => :delivering end event :did_batch_run, :after => :ran_batch do transitions :from => :delivering, :to => :delivered end event :disable do transitions :from => [:pending, :tested, :delivered], :to => :disabled end end def self.new(*args) oo = super oo.body = BODY_TEMPLATE oo end def self.create_with_params(params) obj = self.new params.each { |kk,vv| vv.strip! } obj.update_with_conflict_validation(params) obj end def can_run_batch? self.tested? || self.pending? end def can_run_test? self.test_emails.present? && (self.tested? || self.pending?) end def deliver_batch self.perform_event('do_batch_run!') User.email_opt_in.find_in_batches(batch_size: BATCH_SIZE) do |users| self.email_batch_sets << EmailBatchSet.deliver_set(self.id, users.map(&:id)) end end def test_count self.test_emails.split(',').count end def test_users self.test_emails.split(',').collect do |ee| ee.strip! uu = User.new uu.email = ee uu.first_name = ee.match(/^(.*)@/)[1].to_s uu.last_name = 'Test' uu end end def send_test_batch self.perform_event('do_test_run!') if 'test' == Rails.env BatchMailer.send_batch_email_test(self.id).deliver! else BatchMailer.send_batch_email_test(self.id).deliver end end def merged_body(user) body.gsub(VAR_FIRST_NAME, user.first_name).gsub(VAR_LAST_NAME, user.last_name) end def did_send(emails) self.update_with_conflict_validation({ :sent_count => self.sent_count + emails.size }) if self.sent_count >= self.opt_in_count if delivering? self.perform_event('did_batch_run!') elsif testing? self.perform_event('did_test_run!') end end end def perform_event(event_name) num_try = 0 self.send(event_name) rescue ActiveRecord::StaleObjectError num_try += 1 if 5 > num_try self.reload retry end end def update_with_conflict_validation(*args) num_try = 0 begin update_attributes(*args) rescue ActiveRecord::StaleObjectError num_try += 1 if 5 > num_try self.reload sleep(0.25) retry end end end def will_run_batch self.update_with_conflict_validation({:opt_in_count => User.email_opt_in.count, :sent_count => 0, :started_at => Time.now }) end def will_run_tests self.update_with_conflict_validation({:opt_in_count => self.test_count, :sent_count => 0 }) end def ran_tests self.update_with_conflict_validation({ :completed_at => Time.now }) end def ran_batch self.update_with_conflict_validation({ :completed_at => Time.now }) end def clone bb = EmailBatch.new bb.subject = self.subject bb.body = self.body bb.from_email = self.from_email bb.test_emails = self.test_emails bb.save! bb end def opting_in_count 0 < opt_in_count ? opt_in_count : User.email_opt_in.count end def did_reset self.email_batch_sets.map(&:destroy) self.update_with_conflict_validation({ :opt_in_count => 0, :sent_count => 0, :started_at => nil, :completed_at => nil, }) end end end