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 = 500 BODY_TEMPLATE =<Paragraph 1 ... newline whitespace is significant for plain text conversions

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 state :snapshot 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 event :snapshoting, :after => :take_snapshot do transitions :from => [:pending], :to => :snapshot 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_sets! User.email_opt_in.find_each do |user| bset = EmailBatchSet.sent_email(self, user.id) if 'test' == Rails.env BatchMailer.send_batch_email(self.id, bset.user_id).deliver! else BatchMailer.send_batch_email(self.id, bset.user_id).deliver end end end def deliver_batch self.perform_event('do_batch_run!') self.deliver_batch_sets! end def deliver_batch_async BatchEmailJob.enqueue(self.id) 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 take_snapshot 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 def batch_substitutions(users=[]) {} end def body_for_users(users=[]) self.body end end end