ActionMailer send email in background, queue_classic - ruby-on-rails

I am using queue_classic,
How can I send the following email using queue_classic?
Notifier.welcome(david).deliver # sends the email
UPDATE
I have added a new class method into User class
def.say_hello
puts "hello!"
Notifier.welcome(#david).deliver
end
QC.enqueue("puts", "hello world") works fine,
but QC.enqueue("User.say_hello") doesn't send email"
What could I do?

It looks like queue_classic's enqueue method takes two arguments:
method to call
arguments to pass to this method
So you need to write a method that you can call with the two items above that will deliver your email.
module QueueNotifier
def self.send_welcome_email_to_user(id)
user = User.find(id)
Notifier.welcome(user).deliver
end
end
Then in order to enqueue these sending events, you would queue up the method name (QueueNotifier.send_email_to_user) and the argument (whatever the user id of david or the user you want to send to).
QC.enqueue("QueueNotifier.send_welcome_email_to_user", 14)

Related

Using Twilio API in Ruby, How to pass parameters between actions?

In the ruby controller, I have two methods in the same controller.
class NotificationsController < ApplicationController
def send
my_variable = xxx
twilio_client = Twilio::REST::Client.new account_sid, auth_token
twilio_client.send_text(user, message)
end
def receive
response = Twilio::TwiML::MessagingResponse.new
response.message do |message|
message.body("Hello World!")
end
puts params["Body"]
end
end
The method send would send message to the specific user, and the method receive receive the message from the user. However, the my_variable in the send method lost between actions. I want to use the variable in the receive method, but don't know how to do that.
I tried to assign the variable one to a session hash. session[:variable_one] = variable_one, and access it in the method receive. But it turns out the session[:variable_one] in the method receive is nil.
I read the documents from Twilio, but still very confuse how to pass the extra parameters.
Could you please have some suggestions on this problem? Thanks so much.

Sending email as a job on ruby on rails

Good day everyone,
I created a mailer to send an email to my client. As of right now im still testing it, but I couldn't make it to work. I've read redis, sidekiq, rails_mailer and still nothing. I can see that the mail is in the queue of sidekiq UI but I cant receive the email.
Here's the flow of my code.
User will check the text box on the view if they wanted to send an email to a client.
I a method will be triggered on the controller. Heres my code.
def send_workorder_message
if params.has_key?(:to_send_email)
WorkorderMessage::WorkorderMessageJob.perform_in(10.seconds, #curr_user, params[:message])
end
endv
then a workorder job is created. heres the code.
class WorkorderMessage::WorkorderMessageJob
# include SuckerPunch::Job
include Sidekiq::Worker
sidekiq_options queue: 'mailers'
def perform(user, message)
Spree::WorkorderMailer.workorder_send_to_email(user, message).deliver_now
# ActiveRecord::Base.connection_pool.with_connection do
# end
end
end
after that it will trigger the WorkorderMailer heres the code.
class WorkorderMailer < BaseMailer
def workorder_send_to_email(to_user, message)
ActiveRecord::Base.connection_pool.with_connection do
subject = "sample message mailer"
#message = message
#user = to_user
mail(
to: #user.email,
# 'reply-to': Spree::Store.current.support_address,
from: Spree::Store.current.support_address,
subject: subject
)
end
end
end
when I use the preview mailer I can see the UI working fine.
Also I've noticed that on sidekiq view I see this User Obj. I that normal?
According to the Sidekiq documentation, the arguments you pass must be primitives that cleanly serialize to JSON, and not full Ruby objects, like the user you are passing here:
Complex Ruby objects do not convert to JSON, by default it will
convert with to_s and look like #<Quote:0x0000000006e57288>. Even if
they did serialize correctly, what happens if your queue backs up and
that quote object changes in the meantime? Don't save state to
Sidekiq, save simple identifiers. Look up the objects once you
actually need them in your perform method.
The arguments you pass to perform_async must be composed of simple
JSON datatypes: string, integer, float, boolean, null(nil), array and
hash. This means you must not use ruby symbols as arguments. The
Sidekiq client API uses JSON.dump to send the data to Redis. The
Sidekiq server pulls that JSON data from Redis and uses JSON.load to
convert the data back into Ruby types to pass to your perform method.
Don't pass symbols, named parameters or complex Ruby objects (like
Date or Time!) as those will not survive the dump/load round trip
correctly.
I would suggest you change it to lookup the User by ID within the job, and only pass the ID instead of the entire user object.
# pass #curr_user.id instead of #curr_user
WorkorderMessage::WorkorderMessageJob.perform_in(10.seconds, #curr_user.id, params[:message])
# accept the ID instead of user here
def perform(user_id, message)
# get the user object here
user = User.find(user_id)
# send the mail
mail(
to: user.email,
#...
end

Why do I need to require 'mail' on top of controller to use it outside ActionMailer?

I noticed that Mail gem doesn't get loaded outside ActionMailer context, but the gem is present in the proper gem group of Gemfile and then "loaded" upon Rails initialization.
To create a Mail object in a controller using Mail.new I need to put
require 'mail'
at the top of example_controller.rb, before
class ExampleController < ApplicationController
Could someone explain to me why?
Background:
I need to build an app whose functionality is primarily based on receiving emails of various types. I need to expose only one email address, where people will send all of these emails.
My mail server will pipe the raw email to a ruby script that sends the raw email as a POST request to my app.
Then, I need to identify which kind of email has arrived inferring that from its content (primarily attachments).
For example, let's have emails of types A, B and C. My email processing function will call one of three methods once it identifies the type of the email.
Where should I put the processing function?
You shouldn't be creating mail objects in your controllers. You should create a mailer and then call that mailer from your controller to send any emails you need to.
For example, say you have the following mailer in app/mailers/customer_mailer.rb:
class CustomerMailer < ActionMailer::Base
def send_reminder(user)
#user = user
mail to: user.email, subject: 'Reminder'
end
end
You can then call this from your controller as needed:
class ExampleController < ApplicationController
def some_action
#user = User.find(params[:id])
CustomerMailer.send_reminder(#user).deliver_now
end
end
This way your controller can focus on the implementations specific to controlling the request, and leave the mailer to worry about how to send email.
It's worth noting you also have access to a deliver_later method if you're using a background job runner.
Take a look at the documentation for more details: http://guides.rubyonrails.org/action_mailer_basics.html

How do you trigger the evaluation of a mail method using RSpec?

class MyMailer < BaseMailer
def send_login_prompt
User.reset_login
# ...
end
end
describe MyMailer do
context "when sending a login prompt" do
it "should reset the user's password" do
expect(User).to receive(:reset_login)
MyMailer.send_login_prompt
end
end
end
The incarnation of the test above fails
In the example above we've got a mailer method that triggers a user's password to be
reset. We want to test for that. However when you run the test, .send_login_prompt
does not get called.
In order to actually trigger the code to be evaluated you have to add a line to
inspect the mail object:
Test that works
it "should reset the user's password" do
expect(User).to receive(:reset_login)
mail = MyMailer.send_login_prompt
mail.body # after this line is added the mail is built and the test passes
end
Why is the method not called before and what's the most correct way to prompt the
method to be evaluated rather than the ad-hoc route of calling mail.body?
The mail is not delivered until you access it's content or you can one of the .deliver functions.
This should get the job done nicely
mail = MyMailer.send_login_prompt.deliver_now

Cannot pass the value to the method for delivering email using delayed job gem

I am using an special approach to deliver email.
First, I abstract the call of method for delivering email into a control method send_email
Second, I delayed the execution of the control method.
It seems to be fine to send some value that are hard-coded into the method for delivering email, but not the value passed into that method.
Control method:
# this method is being delayed to control the time of sending email
def send_email
# approach 1 : just send a email after method send_email is executed
# In delay situtation : after 2 minutes
# Otherwise : no delay
Notifier.create_long_task(1234).deliver
# approach 2: explicitly states to delay sending email process
# (same result with the above one)
#
# Notifier.delay.create_long_task(1234)
end
handle_asynchronously :send_email, :run_at => Proc.new { 2.minutes.from_now }
In the above codes, I passed 1234 into delivering method and below the delivering method will assign 1234 to an instance variable #id
def create_long_task(longTask_id)
#greeting = "Hi"
#longTask ="delay setting"
#id = longTask_id
mail to: "j-#hotmail.com", :subject => 'Long Task Created'
end
The email template looks like :
Notifier#create_long_task
Instance variable 1 : <%= #greeting %>
Instance variable 2 : <%= #longTask %>
Instance Id : <%= #id %>
You created a long task
So to be optimistic, the email will show 3 instance variables, 2 are hard-coded in the delivering method, one is passed into delivering method from outside
But the results only can show 2 instance variables that are hard-coded in the delivering method.
Notifier#create_long_task
Instance variable 1 : Hi
Instance variable 2 : delay setting
Instance Id :
You created a long task
It is very strange.
When I comment out handle_asynchronously to send the email without any delay, I can see all the instance variables. So I think that 1234 cannot be passed into delivering method.
Result of no delay email just like:
Notifier#create_long_task
Instance variable 1 : Hi
Instance variable 2 : delay setting
Instance Id : 1234
You created a long task
This is a very long,complicated problem statement, I really appreciate if anyone can solve this problem.
Don't forget to restart delayed job as it won't pick up changes to your code until you do.

Resources