Untuk itu saia memutuskan untuk membuat mailer yang dapat dijadwalkan, selain dapat mengirimkan email pada tanggal dan waktu tertentu, email jg dikirimkan secara berkala pada jangka waktu yg ditentukan (asumsi saia akan dibutuhkan nantinya untuk email laporan berkala.)
Buat Scheduler
Pertama, install rufus-scheduler
gem install rufus-scheduler
lalu dalam folder config/initializers buat file ruby baru, misal "task_scheduler.rb"
scheduler = Rufus::Scheduler.start_new
scheduler.every("10m") do
QueuedEmail.deliver_all
end
yang akan menjalankan deliver_all pada model QueuedEmail setiap 10 menit.
Buat Model utk menyimpan jadwal
generate model baru, misal queued_email
migration:
class CreateQueuedEmails < ActiveRecord::Migration
def self.up
create_table :queued_emails do |t|
t.string :from, :limit => 100
t.string :recipients, :limit => 100
t.string :subject, :limit => 100
t.text :content
t.integer :duration
t.datetime :send_at
t.datetime :last_sent_at
t.timestamps
end
end
def self.down
drop_table :queued_emails
end
end
model:
class QueuedEmail < ActiveRecord::Base
validates_presence_of :from
validates_length_of :from, :within => 6..100
validates_presence_of :recipients
validates_length_of :recipients, :within => 6..100
def recurring?
!self.duration.blank?
end
def deliver!
puts "Sending email: #{self.inspect}"
UserMailer.deliver_custom_mail self.attributes
if recurring?
puts "set sent at: #{Time.now.utc}"
self.update_attribute :last_sent_at, Time.now.utc
else
puts "destroy"
self.destroy
end
end
def self.deliver_all
mails = self.all :conditions => ["(send_at <= :current_time) AND (duration IS NULL OR duration = \"\" OR last_sent_at IS NULL OR TIME_TO_SEC(TIMEDIFF(:current_time, last_sent_at)) >= duration)", {:current_time => Time.now.utc}]
mails.each do |mail|
mail.deliver!
end
end
end
cara kerja:
- duration: bila diisi, setelah email dikirim, email tidak akan langsung dihapus, tetapi akan dikirimkan kembali setiap duration detik
- send_at: menentukan tanggal dan waktu email akan dikirim atau dikirim pertama kalinya bila duration ditentukan.
- last_sent_at: tidak perlu diisi, digunakan secara internal untuk email berkala
- lainnya: rasanya sudah cukup jelas, sama seperti actionmailer
Tambahkan custom_mail di mailer
Saia menggunakan UserMailer < ActionMailer::Base untuk mengirimkan email, tambahkan kode berikut di dalamnya:
def custom_mail(options)
@recipients = options["recipients"]
@from = options["from"]
@subject = options["subject"]
@sent_on = Time.now
@body[:content] = options["content"]
end
dan buat custom_mail.erb di viewnya:
<%= @content %>
Contoh penggunaan
Misalkan untuk mengirimkan survey email 2 hari setelah user register. Tambahkan kode berikut di users_controller create:
# ....
# bila registrasi sukses daftarkan email untuk dikirim setelah 2 hari
QueuedEmail.create(
:send_at => 2.days.since(Time.now.utc),
:from => "\"Site Keren\"",
:recipients => "#{@user.email}",
:subject => "Survey supaya keren" ,
:content => "Halo #{@user.name}, isi survey berikut supaya kamu makin keren gitu loh ....."
)
# ....
untuk email berkala, tentukan duration dalam detik, misal email yg dikirim tiap hari
:duration => 24.hours
Dan segitu saja, mungkin bukan implementasi yg terbaik, tp paling tidak bisa digunakan hehe..