exception handling in ruby on rails - ruby-on-rails

I am a newbie to ruby on rails and developing some email apps, which uses AWS SES to send emails. I am uploading a csv file which contains only email address and an email will be sent to those email address.
Its a very basic app, which my app fails to send an email due to some reasons the app automatically stops sending emails. But I has to keep sending emails to the remaining email address.
How do I handle the exception. I have used ActionMailer.
Kindly Help me

def send_all_emails
#emails.each do |email|
send_one_mail email
end
end
def send_one_mail email
# your actual email sending code here
rescue
# this will log error to Rails log, but will not halt the whole app
Rails.logger.error $!
end

If you want to know about the exception,use
begin
#some code here
rescue =>ex
Rails.logger.error "#{ex.class.name} : #{ex.message}"
end
ps: You can also use rescue Exception =>ex .But don't use it until needed.Since it will catch all minor exceptions like 'NoMemoryError' which we don't want.Use the first one,it will catch only the Standard errors.

Related

Sidekiq Active Job database rollback on error

I'm noticing that when a Sidekiq / Active Job fails due to an error being thrown, any database changes that occurred during the job are rolled back. This seems to be an intentional feature to make jobs idempotent.
My problem is that the method run by the job can send emails to users and it uses database modifications to prevent re-sending emails. If the database change is rolled back, then the email will be resent whenever the job is retried.
Here's roughly what my job looks like:
class ProcessPaymentsJob < ApplicationJob
queue_as :default
def perform(*args)
begin
# This can send emails to users.
PaymentProcessor.perform
rescue StandardError => error
puts 'PaymentsJob failed, ignoring'
puts error
end
end
end
The job is scheduled to run periodically using sidekiq-scheduler. I'm using rails-api v5.
I've added a rescue to try to prevent the job from rolling back the database changes but it still happens.
It occurred to me that maybe this isn't a Sidekiq issue at all but a feature of Rails.
What's the best solution here to prevent spamming the user with emails?
It sounds like your background job is doing too much. If sending the email has no bearing on whether the job was successful or not you should break the job into two jobs: one to send the email and another to do the other bit of processing work.
Alternatively, you could use Sidekiq Batches and make the first job above dependent on the second executing successfully.
Happy Sidekiq’ing!
You could wrap the database changes in a transaction inside of the PaymentProcessor, rescue the database rollback, and only send the email if the transaction succeeds. Sort of like this:
# ../payment_processor.rb
def perform
ActiveRecord::Base.transaction do
# AllTheThings.save!
end
rescue ActiveRecord::RecordInvalid => exception
# if things fail to save, handle the exception however you like
else
# if no exception is raised, send your email
end

Is there any way to prevent Rails autocleaning class variables when testing emails?

I testing a Rails application that sends emails in some situations. It's an API.
For the testing, I'm using the Airborne gem, which makes API testing pretty easy. All went correct except when I had to test the email deliveries. I tried the following:
it "blah" do
//Code that makes my API send an email
puts ActionMailer::Base.deliveries.inspect
end
But deliveries array is always empty. I also tried with Emails.deliveries.inspect. Emails is my custom Mailer that inherits ActionMailer::Base.
I ended reading the API documentation of ActionMailer and met the interceptor concept. Interceptors doesn't work in :test delivery method so I switched to :smtp. In fact, the emails are being sent correctly, but I can not access them on the tests to make expectations.
My interceptor code is this right now
initializers/email_interceptor.rb
class EmailInterceptor
##msgs = []
def self.delivering_email(message)
puts message
//Rails.logger.debug "Email being sent: " + message.to_s
##msgs << message
Rails.logger.debug "Actual messages array: #{##msgs}"
end
def self.msgs
##msgs
end
end
ActionMailer::Base.register_interceptor(EmailInterceptor)
All OK. The debug messages print the array being populated correctly. But the variable is cleaned before my test statement is executed.
EDIT: The code above is executed when I run my test suite. But the variable is empty accessed from the test itself.
//test code
puts EmailInterceptor.msgs.inspect
=> []
Is there any way to prevent this behavior?
You may have config.action_mailer.perform_deliveries = false in your test.rb config. It seems like you should really be using config.action_mailer.delivery_method = :test since this will allow ActionMailer::Base.deliveries to be populated, which makes for easier and more reliable testing. Do you really need interceptors for your tests?

Rails Exception Notification without middleware

I have an Rails 4 application that is entirely comprised of rails runners over cron generated from the whenever gem.
I'd like to be notified if there are any exceptions that occur during the run. The exception_notification gem only runs as rack middleware (web requests only), so it doesn't handle rails runners.
Any ideas? I'm looking to get notified over email or on slack.
You can use ExceptionNotifier.notify_exception in a rescue block to send a notification.
For example:
def rescue_exception(data)
yield
rescue => e
ExceptionNotifier.notify_exception(e, data: data)
end
every :hour do
rescue_exception(runner: 'SomeModel.some_method') do
runner "SomeModel.some_method"
end
end
Please refer to https://github.com/smartinez87/exception_notification#background-notifications. Use data hash to pass additional information about the context.

SMTP errors at sending emails with ruby on rails

I've been trying to send some test newsletter using my gmail account as smtp, but when i tried to send to multiple recipients - ['emai#laddr#email.com, emailaddr2#email.com'] - in this case the first email address is incorrect - it gives me an error 555 - 5.5.2 Syntax error and the process stops without passing through the next email addreses.
My question is:
is there a possibility to bypass those kind of errors in order to skip the incorrect addresses and to continue sending the emails?
You can set ActionMailer to ignore delivery errors, but that's not really considered best practice in a production environment.
# environment.rb (or development/test etc)
ActionMailer::Base.raise_delivery_errors = false
If you don't have a lot of recipients, you could try looping through the array of addresses and sending an email for each one, rescuing a delivery error and adding a message to the log.
# Model
def send_emails(addresses)
addresses.each do |address|
begin
YourMailer.deliver_method(email)
rescue
logger.error "Could not send email to #{email}"
end
end
end

Problems with ActionMailer: 501 <>: missing or malformed local part

I'm having trouble sending mail using SMTP from a Rails app. I have a Mailer class:
class Mailer < ActionMailer::Base
def newsletter_confirmation(subscription)
recipients "my-valid-email#gmail.com" # this is set to my email
# just for testing purposes and will
# be changed to subscription.email
from "\"my-valid-helo-domain.net\" <noreply#my-valid-helo-domain.net>"
subject "Confirm your subscription"
body :subscription => subscription
end
end
When I try to send the mail, I get a Net::SMTPSyntaxError:
501 <["noreply#my-valid-helo-domain.net"]>: missing or malformed local part
If I comment out the from field, the mail gets delivered ok, but with the from information missing (obviously). Any ideas on what I'm doing wrong?
Thanks.
Edit: I'm using Rails 2.3.2 and Ruby 1.9.1
The error code and the description of the error states that this is an error on the mail server.
I suggest you check the mail servers to pinpoint the error.
When it comes to ActionMailer it is supposed to raise an exception if the configuration parameter raise_delivery_errors is set (default in Production but not in Development I believe), so you can check that one and try to resend if it triggers.
EDIT:
Here is the solution (it's a Ruby/Rails 1.9 bug):
https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2340-action-mailer-cant-deliver-mail-via-smtp-on-ruby-191
and the patch:
https://rails.lighthouseapp.com/projects/8994/tickets/2340/a/104008/action_mailer-ruby-1.9-from-address-fix.patch
It is a known bug. https://rails.lighthouseapp.com/projects/8994/tickets/2340

Resources