rescuing from Mysql2::Error - ruby-on-rails

I have a simple question. I have a join table which has an index that ensure that (col 1, col 2) is unique.
I am adding to that table using mysql2 gem and am trying to catch the Mysql2::Error if the attempt results in a duplicate key error. While I am getting the duplicate key error, my rescue body is not being executed.
begin
self.foo << bar
rescue Mysql2::Error
logger.debug("#{$!}")
end
I am receiving the following error upon executing self.foo << bar
Mysql2::Error: Duplicate entry '35455-6628' for key 'index_foos_bars_on_foo_id_and_bar_id': INSERT INTO foos_bars (foo_id, bar_id) VALUES (35455, 6628)
BUT my rescue statement is not being hit! The exception is not be successfully rescued from. What am I doing wrong? If I remove Mysql2::Error and rescue for everything, then it works. But that is bad practice - I just want to rescue from Mysql2::Error which in the event of a duplicate entry.
Thanks,

Mysql2::Error is wrapped in another exception class now. Change your code to:
begin
self.foo << bar
rescue Exception => e # only for debug purposes, don't rescue Exception in real code
logger.debug "#{e.class}"
end
...and you'll see the real exception class that you need to rescue.
Edit: It seems in this case it turned out to be ActiveRecord::RecordNotUnique

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.

Handle exception in ruby on rails

I called a method #txt.watch inside model from worker and Inside watch() there is an array of parameters(parameters = self.parameters). Each parameter have unique reference id.
I want to rescue each exception error for each parameter from inside worker.
class TextWorker
def perform(id)
#txt = WriteTxt.find(id)
begin
#txt.watch
total_complete_watch = if #txt.job_type == 'movie'
#txt.total_count
else
#txt.tracks.where(status:'complete').size
end
#txt.completed = total_completed_games
#txt.complete = (total_complete_games == #txt.total_count)
#txt.completed_at = Time.zone.now if #txt.complete
#txt.zipper if #txt.complete
#txt.save
FileUtils.rm_rf #txt.base_dir if #txt.complete
rescue StandardError => e
#How to find errors for each reference_id here
raise e
end
end
end
Is there any way to do. Thanks u very much.
I assume self.parameters are in your Model class instance. In that case, do as follows and you can reference them.
begin
#txt.watch
rescue StandardError
p #parameters # => self.parameters in the Model context
raise
end
Note:
As a rule of thumb, it is recommended to limit the scope of rescue as narrow as possible. Do not include statements which should not raise Exceptions in your main clause (such as, #txt.save and FileUtils.rm_rf in your case). Also, it is far better to limit the class of an exception; for example, rescue Encoding::CompatibilityError instead of EncodingError, or EncodingError instaed of StandardError, and so on. Or, an even better way is to define your own Exception class and raise it deliberately.

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

Yelp API exception Handling Ruby on Rails

I'm working on Yelp API through gem 'yelp' . Everything works fine but when we enter a location which is not provided by yelp it throws exception .
Yelp::Error::UnavailableForLocation
I have tried begin/end raise and rescue but not working . Can anyone tell , what's i'm doing wrong . here is what i tried
begin
client = Yelp::client
raise yelp_places_burst = client.search('lahore , pakistan')
end
rescue Exception => e
puts e.message
In addition , I want to send the error to js file (in response of ajax)
You are a little bit confused on how an exception is rescued. The way to rescue an exception in Ruby is
begin
# execution
rescue ErrorClass
# do something
end
Therefore your code should be
begin
client = Yelp::client
yelp_places_burst = client.search('lahore , pakistan')
rescue Yelp::Error::UnavailableForLocation => e
puts e.message
end
Also note I replaced Exception with the specific exception class. In fact, it's not recommended to rescue Exception as it will hide several other very exceptional events.
if you look at https://github.com/Yelp/yelp-ruby/blob/develop/lib/yelp/error.rb you can see that Yelp::Error::UnavailableForLocation is extended from Base which extends StandardError. So you need to catch StandardError, not Exception.
You get some additional explanations here: https://robots.thoughtbot.com/rescue-standarderror-not-exception, which suggests you can use rescue => e which will catch StandardError by default.

Rails handling ActiveRecord::AssociationTypeMismatch as exception

I have the following code:
def set_tags_from_string
list = self.tags_string.split(/ /)
list.each do |tag|
begin
self.partner_tags << PartnerTag.find_by(name: tag)
rescue
self.partner_tags << PartnerTag.create(name: tag)
end
end
end
The problem comes when I try pushing a PartnerTag into self.partner_tags and that tag doesn't exist yet. The console shows the following:
ActiveRecord::AssociationTypeMismatch: PartnerTag(#28272720) expected, got NilClass(#8501040)
I was hoping to be able to handle this as an exception but it still gives the error. I've never done exception handling in Ruby before so I figure I might be missing something, but I followed this tutorial and I don't see what I'm missing. The Rails API says that it is in fact an exception which ends up inheriting from StandardError. The Ruby documentation says that a rescue clause should handle all StandardErrors, so I have no idea what I'm doing wrong.
Try this instead:
self.partner_tags << PartnerTag.find_by(name: tag) || PartnerTag.create(name)
Also if you are on Rails 4, you can do:
self.partners_tags << PartnerTag.find_or_create_by(tag: name)
Note however that it doesn't prevent you from ending up with two identical tags unless you have unique constraint in a database.

Resources