I make an API call to fetch an email address. On success I'd like to pass this email address to another job. I use sidekiq and sidekiq-batch gems.
class HandleWebhookJob
def perform
batch = Sidekiq::Batch.new
batch.description = "Handling webhook"
batch.on(:success, HandleWebhookJob::OtherJob, { email: #email })
batch.jobs do
#email = GetEmailJob.perform_async # returns email address
end
end
class OtherJob
def on_success(status, options)
puts options # no email address here - nil
# need to pass it to UseEmailJob.perfom_async(options[:email])
end
end
end
I assume that assigning the result of GetEmailJob to #email won't work. Can't find an example of how to do this and if it's even possible.
I think that you get jid in #email.
Can you save emails in GetEmailJob to some storage (e.g. redis) with prefix:jid key and take them from there?
Related
I would like to turn off certain emails in development and on test/staging servers, but keep sending them in production. What I currently do is set the default "to" address for these administrative mails to blank:
default :to => Rails.env.production? ? "admin-list#sharethevisit.com" : ""
However, this puts stack traces in my development log when I'm testing the user mails which should be sending.
Is there a more effective way of disabling certain emails based on the current environment? I tried checking in the functions themselves, but is not ideal because I have to change each function, plus it doesn't actually work... it just fails to set the needed #account variable before rendering the email and creating a different stack trace.
def user_registered_notify_email(account)
if Rails.env.production?
#account = account
mail(:subject => "New user registered: #{#account.full_name}")
end
end
I usually use mail interceptors as described here: http://asciicasts.com/episodes/206-action-mailer-in-rails-3
I can't remember where I found this to credit the author but this is how I redirected email in development mode. Create a new file in RAILS_ROOT/config/initializers for this. DEFAULT_DEV_EMAIL_OVERRIDE is defined in our main site config with other static values.
if Rails.env.development?
if Rails.version =~ /^2\./
class ActionMailer::Base
def create_mail_with_overriding_recipients
mail = create_mail_without_overriding_recipients
mail.to = DEFAULT_DEV_EMAIL_OVERRIDE
mail
end
alias_method_chain :create_mail, :overriding_recipients
end
elsif Rails.version =~ /^3\./
if Rails.env.development?
class OverrideMailRecipient
def self.delivering_email(mail)
mail.to = DEFAULT_DEV_EMAIL_OVERRIDE
end
end
ActionMailer::Base.register_interceptor(OverrideMailRecipient)
end
end
end
Consider using an interceptor to set Mail::Message#perform_deliveries to false:
class NeverDeliverInterceptor
def self.delivering_email(message)
message.perform_deliveries = false
end
end
if !Rails.env.production?
ActionMailer::Base.register_interceptor(NeverDeliverInterceptor)
end
See API doc for source & other usage.
I need to send massive email,I will use for brackground job Delayed Job, and have to create the email message in 3 languages (de, en, re), How can I cache the view so it doesn't have to create each time I'm calling the the mail method.
The deliver method is the one that sends the email, so you can do this:
def send_emails
# You can set here the email with attachments and all stuff
mail = MyMailer.send_message("demo#example.com")
body = mail.html_part.body
User.all.each do |u|
mail.to = u.email
mail.html_part.body = body.gsub(/user_id/, u.id)
mail.deliver
end
end
Of course it's better if you set this method for background processing.
I have an app which connects to an iphone app, which in turn authenticates it's users via http_digest.
I'm using authlogic, and in my schema users of the website are "users" and users of the phone app are "people". So, i have user_sessions and people_sessions. To handle the http_digest auth, i'm using the authenticate_or_request_with_http_digest method like this:
def digest_authenticate_person
authenticate_or_request_with_http_digest do |email, password|
#ldb is just a logging method i have
ldb "email = #{email.inspect}, password = #{password.inspect}"
person = Person.find_by_email(email)
if person
ldb "Authentication successful: Got person with id #{person.id}"
#current_person_session = PersonSession.create(person)
else
ldb "Authentication failed"
#current_person_session = nil
end
return #current_person_session
end
end
I can see in the logs that password is nil: only email is passed through to the inside of the authenticate_or_request_with_http_digest block.
Im testing this with a curl call like so:
curl --digest --user fakename#madeup.xyz:apass "http://localhost:3000/reports.xml"
I'd expect "fakename#madeup.xyz" and "apass" to get passed through to the inside of the block. Once i have the password then i can use a combination of email and password to find (or not) a user, in the normal way. Does anyone know how i can get access to the password as well?
grateful for any advice - max
EDIT - on further googling, i think i'm using this method wrong: i'm supposed to just return the password, or the crypted password. But then how do i compare that against the password passed as part of the http_digest username?
Found the answer: i had a fundamental misunderstanding of how authenticate_or_request_with_http_digest works: after reading the documentation (in the source code of the gem) i realised that the purpose of this method is not to do the authentication, its purpose is to provide the "email:realm:password" string to the browser, let the browser encrypt it, and check the result against it's own calculated (or cached) version of this.
Here's how i set it up:
def current_person
if #current_person
#current_person
else
load_current_person
end
end
#use in before_filter for methods that require an authenticated person (mobile app user)
def require_person
unless current_person
redirect_to root_path
end
end
def load_current_person
#check user agent to see if we're getting the request from the mobile app
if request.env['HTTP_USER_AGENT'] =~ /MobileAppName/
result = digest_authenticate_person
if result == 401
return 401
elsif result == true
#make authlogic session for person
#current_person_session = PersonSession.new(#person_from_digest_auth)
#current_person = #person_from_digest_auth
end
end
end
#this method returns either true or 401
def digest_authenticate_person
authenticate_or_request_with_http_digest(Person::DIGEST_REALM) do |email|
person = Person.find_by_email(email)
#result = nil
if person
#need to send back ha1_password for digest_auth, but also hang on to the person in case we *do* auth them successfully
#person_from_digest_auth = person
#result = person.ha1_password
else
#person_from_digest_auth = nil
#result = false
end
#result
end
end
I have a table of emails. And i need that Each user received email.
SO i made:
script/generate mailer Notifier
Next.
class Notifier < ActionMailer::Base
def newgrants_notification(respondent)
recipients user.email
from "lala#lala.com"
subject "Hi!"
body (:respondent => respondent)
end
end
In app/views/notifier/newgrants_notification.erb
wrote : Hello!
and this my controller where i create question
#question = Question.create(:text => params[:question][:text], :security => rand(888).to_i)
if success = #question.save
respondents = Respondent.find(:all)
respondents.each do |res|
Inquiry.create(:question_id=>#question.id.to_i, :respondent_id=>res.id.to_i)
Notifier.newgrants_notification(respondents).deliver #this is right??
end
what mistakes i did? messages aren't coming ;(
HI
respondents.each do |res|
Inquiry.create(:question_id=>#question.id.to_i, :respondent_id=>res.id.to_i)
Notifier.newgrants_notification(res).deliver
end
When you are sending mail,the mail id is passed as a parameter so respondents is replaced with res.
You are passing through your array of respondents, when you use each, the variable in the pipes (|res|) is the one to use to refer to the singular object in the loop.
Notifier.newgrants_notification(res).deliver
In development mode all email are not send. It's all log only in your log file. So if you test on this environment is normal. Check on your log if you see it :)
When trying to send an email to the user for reseting their password, I keep getting an execution timed out error. Other mailer functions work, so I know that the config settings are correct. The header reads: "Timeout::Error in Password resetsController#create"
Here is the password_resets_controller:
def create
#user = User.find_by_email(params[:email])
if #user
User.deliver_password_reset_instructions(#user.id)
flash[:notice] = "Instructions to reset your password have been emailed to you. " +
"Please check your email."
redirect_to '/'
else
flash[:notice] = "No user was found with that email address"
render :action => :new
end
end
Here is the method inside of User.rb
def self.deliver_password_reset_instructions(user_id)
user = User.find(user_id)
user.reset_perishable_token!
Emailer.deliver_password_reset_instructions(user)
end
Finally, here is the actual method inside of emailer.rb:
default_url_options[:host] = "http://0.0.0.0:3000" #development
def password_reset_instructions(user)
#subject = "Application Password Reset"
#from = 'Notice#myApp.com'
#recipients = user.email
#sent_on = Time.now
#body["edit_password_reset_url"] = edit_password_reset_url(user.perishable_token)
#headers["X-SMTPAPI"] = "{\"category\" : \"Password Recovery\"}"#send grid category header
end
Why is "Password" in the error message referred to causing a timeout::error
Sending email (or other long running processes) from the main controller request thread is not a good idea. The sending of the email can time out for a variety of reasons that are not under your control (e.g. the outbound email delivery server being down) and you don't want your application server and users to suffer due to that.
A better approach is to use a queuing mechanism like Delayed Job (DJ) to queue these email tasks, and have them be processed outside of your controller threads.
See https://github.com/collectiveidea/delayed_job
Integration of this (or another queuing system) into your rails app is fairly simple. And rails 4 is said to have built in queuing services (which I'm yet to use) http://blog.remarkablelabs.com/2012/12/asynchronous-action-mailer-rails-4-countdown-to-2013.
For instance, if you use DJ in your app, the new code will look like below
def self.deliver_password_reset_instructions(user_id)
user = User.find(user_id)
user.reset_perishable_token!
# this is the only line that changes
Emailer.delay.deliver_password_reset_instructions(user)
end
The jobs are stored in the database, and re-tried when errors like time outs happen.
You can read more about DJ on the github page.