Rails scheduled SMS sender - ruby-on-rails

I want send an SMS each 5 minutes to my users. At the moment, my application sends an SMS during the creation of an account.
# users_controller.rb
def create
#user = User.new(user_params)
if #user.save
#user.send_activation_email
#user.send_daily_sms
flash[:info] = "Veuillez contrôler votre boîte mail pour activer votre compte."
redirect_to root_url
else
render 'new'
end
end
# user.rb
def send_daily_sms
# put your own credentials here
account_sid = '**********************'
auth_token = '**********************'
# set up a client to talk to the Twilio REST API
#client = Twilio::REST::Client.new account_sid, auth_token
#client.account.messages.create({
:from => '**********',
:to => '***********',
:body => 'Salut',
})
end
I already have scheduled mails working in my project by doing this :
# schedule.rb
every :day, :at => '12pm' do
rake "email_sender_daily"
end
# My task
task :email_sender_daily => :environment do |_, args|
User.find_each do |user|
UserMailer.daily_mail(user).deliver_now if user.daily == true
end
end
# My UserMailer
def daily_mail(user)
#user = user
mail to: user.email, subject: "Mail journalier"
end
I'm showing you this because, with the UserMailer, I know how to access it from an other file. Here, I'd like to do the exactly the same for SMS, but how can I access the method that is in my Model ? If not, where can I put this method to be able to access it from my rake task ?

Twilio developer evangelist here.
It looks to me like you have all the parts you need. If send_daily_sms is a method in your User class then all you require is a rake task like so:
task :sms_sender_daily => :environment do |_, args|
User.find_each do |user|
user.send_daily_sms if user.daily == true
end
end
And then your schedule.rb would look like:
every :day, :at => '12pm' do
rake "email_sender_daily"
rake "sms_sender_daily"
end
I would warn that sending sms messages to all your users via one method that calls the API over and over again is somewhat fragile. If one message fails to send because of a timeout or some other error then the task will throw an error and not be able to complete sending all the messages.
I'd suggest sending both emails and sms messages by workers using a background queue, like Rails's ActiveJob. If you are on the latest Rails 4.2 then you can use a gem called Textris that works much like ActionMailer and then you could define a UserTexter class like this:
class UserTexter < Textris::Base
default :from => YOUR_NUMBER
def daily_sms(user)
#user = user
text :to => #user.phone_number
end
end
Then your tasks could look like this:
task :email_sender_daily => :environment do |_, args|
User.find_each do |user|
UserMailer.daily_mail(user).deliver_later if user.daily == true
end
end
task :sms_sender_daily => :environment do |_, args|
User.find_each do |user|
UserTexter.daily_sms(user).deliver_later if user.daily == true
end
end
Check out the Textris documentation for more on how to use the gem.
Let me know if this helps at all!

Related

Ruby on Rails - Get user email from database in a Rake Task

I have that Mailer method and a Rake task to later scheduled with Cron Job and automate with Gem Whenever for send a email to a users:
# Mailer:
class MailCourseWarnMailer < ActionMailer::Base
def course_available(user)
#user = user
mail(to: #user.email, subject: "Curso disponível") # ... email sending logic goes here
end
end
# Task
require 'rake'
desc 'send digest email'
task :send_warn_course, [:user_email] => :environment do |t, args|
user = MailCourseWarn.find_by_email args[:user_email]
MailCourseWarnMailer.course_available(user).deliver!
end
# Model
class MailCourseWarn < ActiveRecord::Base
belongs_to :course
validates :name, :email, presence: true
end
I am currently run the task like this: rake send_warn_course['user#email.com'] but I need that this be automatic, in a way that when run rake send_warn_course the Rake Task send to all of users in my DB.
Any ideas How can I do that? Thanks.
Find the user(s) that need the email and iterate over them. Surely you're indicating which users need the email in the database somehow, so you'll just want to query all those user records, iterate over them, and then send the email.
task :send_warn_course, [:user_email] => :environment do |t, args|
MailCourseWarn.where(needs_warned: true).each do |user|
MailCourseWarnMailer.course_available(user).deliver!
end
end

undefined method `company_name' for nil:NilClass Rails mailer views not rendering variables from controller

I have setup a Task that check for all the followups that are outstanding by a date. I have now send up a task that will run and check for outstanding follow ups for the day and send out an email reminder. All working i think but i can't get the values to show in the Email itself it keep giving me a NilClass error.
rake aborted!
undefined method `company_name' for nil:NilClass
This task i am running through rake at the moment as it will be running through Cron (Whenever gem) which all is working.
Thanks in Advance Code is Below
lib/tasks/daily.rake
namespace :notifications do
desc "Sends notifications"
task :send => :environment do
Followup.where(:closed => false, :quotefdate => (8640.hours.ago..Time.now)).each do |u|
FollowupMailer.followup_confirmation(#followup).deliver
end
end
end
followup_mailer.rb
class FollowupMailer < ActionMailer::Base
default :from => "from#email.com"
def followup_confirmation(followup)
#followup = followup
mail(:to => 'my#email.com', :subject => "Follow up Required")
end
end
followup_confirmation.text.erb
Good Day
Please action this follow up.
<%= #followup.company_name %>
Kind Regards
Mangement
The error source is located in this rake task:
namespace :notifications do
desc "Sends notifications"
task :send => :environment do
Followup.where(:closed => false, :quotefdate => (8640.hours.ago..Time.now)).each do |u|
FollowupMailer.followup_confirmation(#followup).deliver
end
end
end
You're trying to use #followup instance variable, which is unset. Instead, you should use u passed into block:
namespace :notifications do
desc "Sends notifications"
task :send => :environment do
Followup.where(:closed => false, :quotefdate => (8640.hours.ago..Time.now)).each do |u|
FollowupMailer.followup_confirmation(u).deliver # use u variable here
end
end
end

running rake task from console produces 'ArgumentError: no method name given' error

I have a rake task that is meant to call a Mailer and email certain users that meet a given condition. But, when I call the rake task from the console using rake nagging_email:send
I get the following 'ArgumentError: no method name given' and the task does not run. The full console error log can be seen here: https://gist.github.com/srt32/6433024
I have a mailer set up as follows:
class WorkoutMailer < ActionMailer::Base
def nagging_email(user)
#user = user
subject = "What have you done today?"
#url = 'http://frozen-taiga-7141.herokuapp.com/members/sign_in'
mail to: #user.email,
subject: subject.to_s
end
end
and then a rake task as follows that gets all the users that meet a given condition (being lazy) and then calls the Mailer given that user as a param:
namespace :nagging_email do
desc "send nagging email to lazy users"
task :send => :environment do
daily_nag
end
def daily_nag
users = User.all
users.each do |user|
unless last_workout(user) == Date.today
WorkoutMailer.nagging_email(user).deliver
end
end
end
def last_workout(user)
user = user
last_workout = user.workouts.order("date DESC").limit(1)
last_workout_date = last_workout.date
return last_workout_date
end
end
Any help trying to figure out how run this rake task would be appreciated. Thanks.
You should run rake from terminal, not rails console.
If you for some reason want to do it from rails console, you should load tasks like that
require 'rake'
MyRailsApp::Application.load_tasks
Rake::Task['my_task'].invoke

ActionMailer::Base.deliveries always empty in Rspec

I'm trying to test some mailers with rspec but deliveries are always empty. Here is my rspec test:
require "spec_helper"
describe "AccountMailer", :type => :helper do
before(:each) do
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
end
it "should send welcome email to account email" do
account = FactoryGirl.create :account
account.send_welcome_email
ActionMailer::Base.deliveries.empty?.should be_false
ActionMailer::Base.deliveries.last.to.should == account.email
end
end
It fails with:
1) AccountMailer should send welcome email to account email
Failure/Error: ActionMailer::Base.deliveries.empty?.should be_false
expected true to be false
My send_welcome_email function looks like this ( that's my model ):
def send_welcome_email
AccountMailer.welcome self
end
And my mailer:
class AccountMailer < ActionMailer::Base
default from: APP_CONFIG['email']['from']
def welcome data
if data.locale == 'es'
template = 'welcome-es'
else
template = 'welcome-en'
end
mail(:to => data.email, :subject => I18n.t('welcome_email_subject'), :template_name => template)
end
end
Any ideas? I'm not sure about how to proceed.
Have you tested that it's working when you're actually running the app? Perhaps your test is correct to be failing.
I noticed that you're never calling deliver when you create the mail, so I suspect that the test is failing because email is, in fact, not getting sent. I would expect your send_welcome_email method to look more like
def send_welcome_email
AccountMailer.welcome(self).deliver
end

Authlogic & delayed_job & delayed_jobl_mailer & daemons?

[edit] I can delay all mail using delayed_job plugin on a shared server with a daemon… except the mail using authlogic.
I don't know where I have to search, and why it is working in other way.
daemons (off) delayed_job & delayed_mail_mailer (on) authlogic (reset_password) : send
daemons (on) delayed_job & delayed_mail_mailer (on) other_model (send_mail) : send
daemons (on) delayed_job & delayed_mail_mailer (on) authlogic (reset_password) : nothing !
Where to search the problem ??
app/initializer/delayed_mailer.rb :
class ActionMailer::Base
include Delayed::Mailer
end
config/initializers/delayed_job_config.rb :
Delayed::Job.destroy_failed_jobs = false
silence_warnings do
Delayed::Job.const_set("MAX_ATTEMPTS", 3)
Delayed::Job.const_set("MAX_RUN_TIME", 5.minutes)
end
script/dalayed_job :
#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
daemon_options = {
:multiple => false,
:dir_mode => :normal,
:dir => File.join(dir, 'tmp', 'pids'),
:backtrace => true,
:log_output => true
}
Daemons.run_proc('delayed_job', daemon_options) do
Dir.chdir dir
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
require File.join('config', 'environment')
Delayed::Worker.new.start
end
model/controllers/passwoed_reset_controller.rb
def create
#user = User.find_by_email(params[:email])
if #user
Notifier::deliver_password_reset_instructions(#user)
flash[:notice] = t('ResetInstructionSend') + t('CheckMail')
redirect_to root_url
else
flash[:notice] = t('NoUserMail')
render :action => :new
end
end
controllers/other_controller.rb
def update
#patent = Patent.find(params[:id])
# update all
#patent.update_attributes(params[:patent])
#user = #patent.user
#skill = #patent.skill
#current_user = current_user
Notifier::deliver_specialist_confirmation(#user, #skill, #current_user)
end
models/notifier.rb
def password_reset_instructions(user)
recipients user.email
from "Skill Forest"
subject "Password Reset Instructions"
body :edit_password_reset_url => edit_password_reset_url(user.perishable_token),:user => user
end
def specialist_confirmation (user, skill, current_user)
recipients user.email
from "Skill Forest"
subject "Bravo"
body :user => user, :skill => skill, :current_user => current_user
end
More infos : Rails 2.3.5 & tobi delayed_job & daemons 1.0.10
I'm on dreamhost shared web hosting, but look the same on development mode on my computer.
[Edit 2] I will control to be sure, but seems it was only the max run time too short…
[Edit 3] an other way I'm trying : control if pid exist
Just to turn the page… passing in Rails 3 and updating gem… everything fine. And much simpler.
Mystery of binary coding !

Resources