Ruby rescue multiple specific errors - ruby-on-rails

In Rails i am trying to validate dates that are being imported through an excel document. it wont go through ActiveRecord so i cant use the Timeliness gem that i have in the system that i use to verify other dates.
So i wrote my own gem that verifies the format of a date, but there are some dates that get through that are not valid like 31/04/2013, if the date is in an incorrect format then it will raise a RuntimeError which i rescue and supply a error message. but in ruby:
Date.new(2013,4,31)
ยป ArgumentError: invalid date
So i would like to rescue either of them. i am just afraid that some ArgumentError will appear and it wont be this exact one. so i would like it to rescue only ArgumentError: invalid date, is this possible?
This is the excel date checker i wrote
def as_date
return nil if self.blank?
begin
date = DateDojo::DateSensei.date_format_validation(self)
if date.class == Date
return date
else
return false
end
rescue RuntimeError
:invalid_date_format_to_make_validations_cry_and_die_sad_face
rescue ArgumentError
:dates_that_wouldnt_exist_even_in_the_correct_format
end
end

You can target a specific error message like so:
begin
...
rescue ArgumentError => e
if e.message =~ /invalid date/
# Do something
else
puts e.message
end
end

Related

Exception not falling in models

I wrote a function in ruby on rails model like below
def sorted_exp
begin
exp.order("currently_active = true DESC, TO_DATE(to_date, 'MM-DD-YYYY') DESC")
rescue
exp.order("currently_active = true DESC")
end
end
but there are few entries in to_date column due to which exception falls like 'september 2018'. When I tried to handle exception in model, it failed, and does not go in the rescue section. I don't know why it does not catch the error in model here, and why it does not return a query in the rescue section.
The exception raised is the following:
PG::InvalidDatetimeFormat: ERROR: invalid value "se" for "MM"
In the sorted_exp method, the output of the query is not being used. Rails actually executes the call to the DB when the value of the call is being used. In this case, the value of this is probably being used in some other function and the error is being raised from there, pointing to this line: exp.order("currently_active = true DESC, TO_DATE(to_date, 'MM-DD-YYYY') DESC")
I'm not sure of your exact use case, but the only way of catching the exception in this block would be to use values that the query is supposed to return, like counting the number of objects returned(Again, it depends on your use case).
For example, the following query raises an error inspite of being in a begin..rescue block:
begin
User.order("TO_DATE(users.created_at, 'MONTH-YYYY') DESC")
rescue
puts "In rescue block"
end
This raises the following error:
ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR: function to_date(timestamp without time zone, unknown) does not exist
However, when the output of this query is used in the begin block itself, the exception gets caught. For example:
begin
sorted_users = User.order("TO_DATE(users.created_at, 'MONTH-YYYY') DESC")
count = sorted_users.count
rescue
puts "In rescue block"
end
The output for this is:
In rescue block
This is because the query was actually executed in the begin block itself, and hence, got caught by our rescue block.

Rescue PG::UndefinedTable instead of ActiveRecord::StatementInvalid

If I try to, for example, drop a table that doesn't exist, I will get the following error:
"#<ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: relation \"aiurea\" does not exist\n
I can rescue from it using ActiveRecord::StatementInvalid, but it's too generic for me; I would like to only rescue when the underlying error is PG::UndefinedTable. How can I do this?
P.S.: I saw error.cause to lead to the underlying error, but I'm not sure whether this is "public" interface and it is an unobtrusive way to get to it.
2018 Update:
ex.original_exception has been deprecated in favor of ex.cause. This worked for me:
rescue ActiveRecord::StatementInvalid => ex
if ex.cause.is_a?(PG::UndefinedTable)
# do something
else
raise ex
end
end
ActiveRecord::StatementInvalid is a special Error type that encapsulates other errors in it. You can access the original one with .original_exception:
rescue ActiveRecord::StatementInvalid => ex
ex.original_exception # this will return the `PG::UndefinedTable` class, which you can further inspect.
end
Better way to do is:
rescue ActiveRecord::StatementInvalid => ex
if ex.original_exception.is_a?(PG::UndefinedTable)
# do something
else
raise ex
end
end
Something like this should work
rescue ActiveRecord::StatementInvalid => ex
if ex.message =~ /PG::UndefinedTable/
// Do stuff here
else
raise ex
end
end

Ruby on Rails How to treat a error from a method call

I have this ruby code:
def get_last_quote(ticker)
todays_date = Date.today
data = YahooFinance::Scraper::Company.new(ticker.downcase).historical_prices(todays_date, todays_date)
return data.first[:close]
end
When today's date is Sunday or Saturday I don't want any data, because markets are closed. Same thing happens on holidays or for any other day when the markets are closed.
So if it fails I want to subtract 1 from the days and check again, until I find a valid day.
The problem is that when the day is not valid I get Ruby on Rails error and I don't know how to treat it.
I tried:
while data.nil?
But it does not work, the error happens when I try to attribute the result to data, so I don't have a chance to check whether data is valid or not.
Any ideas, is it possible?
use begin then rescue ErrorClass with finally end
example
def method(args)
args += 1
end
def call_method
begin
method(92929292)
rescue ArgumentError, e
e.message
end
end

Begin and Rescue block exception handling

I have little experience in rails exception handling. I have this snippet
def update
#game = Game.find(params[:id])
begin
params[:game][:tier] = eval(params[:game][:tier])
rescue
#game.errors.add(:tier, "Please make sure the correct format for tier, example [100, 1000, 10000]")
end
#.... more code
end
In case params[:game][:tier] = "[100,200]" everything is perfect.
In case of error case of ruby syntax like params[:game][:tier] = "[100,200] abc" it catch the error however the application just crush.
How can I handle exception with 'eval()' such that it won't crush the app? Why begin and rescue does not work in this case? Appreciate any help for ruby enlightenment thanks :)
What if params[:game][:tier] was "[100,200]; system('rm -rf /')"?
Since the incoming data is expected to be an array, I would not use eval but JSON.parse instead:
> JSON.parse("[100,200]")
=> [100, 200]
> JSON.parse("[100,200] abc")
JSON::ParserError: 746: unexpected token at 'abc'...
Then rescue from only a JSON::ParserError exception
rescue JSON::ParserError => e
This will also solve the rescue not catching the exception problem you're having.
duplicate of this
however you should rescue in this way
def update
#game = Game.find(params[:id])
begin
params[:game][:tier] = eval(params[:game][:tier])
rescue Exception => e
#game.errors.add(:tier, "Please make sure the correct format for tier, example [100, 1000, 10000]")
end
#.... more code
end
in order to make it work

How do you access database error information when using Rails and Postgres

I am using find_by_sql to connect to a Postgres database and execute a database function. The database function executes a number of SQL statements and raises exceptions as required.
How do I trap the error code and error message raised by the Postgres function in Rails?
def self.validate_email(systemuserid, emailaddress)
begin
result = (self.find_by_sql(["SELECT fn_systemuser_validate_email(?, ?) AS returncode",
systemuserid, emailaddress])).first
rescue => err
# I want to get access to the error code and error message here and act accordingly
# errno = ??
# errmsg = ??
if errno == 10000
end
end
return result[:returncode]
end
I started by trying to find this information in the connection object - no such luck.
Any help much appreciated.
Currently active record replaces the original error with an internal one without passing on the original with the new error. I cant understand why any one would want this.
So the only solution right now is to monkey patch ;)
module ActiveRecord
module ConnectionAdapters
class AbstractAdapter
def translate_exception(e, message)
ActiveRecord::WrappedDatabaseException.new(message,e)
end
# Replaces
# def translate_exception(e, message)
# # override in derived class
# ActiveRecord::StatementInvalid.new(message)
# end
end
end
end
Now you can get the original_exception.
def self.validate_email(systemuserid, emailaddress)
begin
result = (self.find_by_sql(["SELECT fn_systemuser_validate_email(?, ?) AS returncode", systemuserid, emailaddress])).first
rescue ActiveRecord::WrappedDatabaseException => e
pgerror = e.original_exception
# Exact api depends on PG version, check the docs for your version.
puts "Doing my stuff: #{pgerror.result.result_error_message}"
end
end
This works with pg version 0.11 and Rails 3.0.9. Will probably work with later versions.
I let this one go for a while, (9 months!) but picked it up again due to a new impetus.
I used the monkey patch suggested by Darwin (sorry that the pull request didnt get the vote) and have then discovered that the code I need (with reference to http://deveiate.org/code/pg/PG/Result.html) is as follows:
rescue ActiveRecord::WrappedDatabaseException => e
pgerror = e.original_exception
sqlstate = pgerror.result.error_field(PG::Result::PG_DIAG_SQLSTATE )
end
Just look at .cause.
begin
# whatever.
rescue => err
p err.cause
end
You can user the errors array of your model, like others database:
errmsg = YourModel.errors[0].full_messages

Resources