Should the following test assert an exception was thrown? On my pc it doesn't and I want to know if this is expected behavior.
def a
raise RuntimeError
end
def b
begin
a
rescue RuntimeError
puts "bummer"
end
end
test "assert this" do
assert_raises RuntimeError do
b
end
end
It's an intended behavior. assert_raise doesn't check whether an exception is raised somewhere in the script execution, it checks whether the block raises an uncaught exception of given type.
In other words, it works only if you remove the rescue statement.
Related
I'm attempting to debug my code, in order to see if #new_participant is instantiated, but when I place binding.pry around it as displayed below, it hops over the block, and placing the debugger within the block obviously doesn't work either. How do I debug this?
def create_participant!(case_file)
binding.pry
params = participant_params(case_file.case_file.id)
ActiveRecord::Base.transaction do
#new_participant = participant_clazz.create!(params)
assign_private_infos!(participant_id: new_participant.id)
binding.pry
end
call_link_participant_job!
end
You're calling create! which will raise an ActiveRecord::RecordInvalid exception if the record is not valid. Exceptions immediately halt the script execution and Ruby goes up the call stack until a rescue is found (or not).
ActiveRecord::Transactions wraps the block in a rescue which triggers a rollback and then propagates the exception.
Also have in mind that exceptions thrown within a transaction block will be propagated (after triggering the ROLLBACK), so you should be ready to catch those in your application code.
If you want to run code before the rollback you need to rescue the exception inside the block:
def create_participant!(case_file)
binding.pry
params = participant_params(case_file.case_file.id)
ActiveRecord::Base.transaction do
begin
#new_participant = participant_clazz.create!(params)
assign_private_infos!(participant_id: new_participant.id)
rescue ActiveRecord::RecordInvalid => e
binding.pry
raise e # re-raise the exception to trigger a rollback
end
call_link_participant_job!
end
end
Or you can rescue the exception after the rollback:
def create_participant!(case_file)
binding.pry
params = participant_params(case_file.case_file.id)
begin
ActiveRecord::Base.transaction do
#new_participant = participant_clazz.create!(params)
assign_private_infos!(participant_id: new_participant.id)
call_link_participant_job!
end
rescue ActiveRecord::RecordInvalid => e
binding.pry
end
end
I am bit unclear about exception handling while using Active record transactions in rails. I have seen many of them using,
Method: 1
def update
ActiveRecord::Base.transaction do
begin
# Some logic
rescue StandardError => e
raise ActiveRecord::Rollback
end
end
end
and have seen the below logics in many of the places.
Method:2
def update
ActiveRecord::Base.transaction do
if object.update(update_params)
# success
else
# error handling
end
end
rescue => e
# error handling
end
What I think is the second method itself is enough. I thought that, Transaction itself will rollback if anything unexpected happens or any logical error inside the transaction and we can catch them and do whatever we want. Is catching exception inside the transaction and raising Rollback manually needed anywhere?. What is the difference between both the methods and in which case?
You don't need to manually to rollback the transaction the code below should be good enough
def update
ActiveRecord::Base.transaction do
foo.update(foo_update_params)
end
rescue ActiveRecord::RecordInvalid
# Handle your exception here
end
Have a look here for a better explanation.
Why doesn't this work?? I expect the rescue block to be executed if an ActionView::TemplateError is raised. But that isn't happening for some reason...
The following is a controller action in a rails 4 app.
def categorized
#ActionView::TemplateError raising code
rescue ActionView::TemplateError
binding.pry
end
how about if move exception in application_controller.rb:
rescue_from ActionView::TemplateError do | exception |
binding.pry
end
Try with
rescue => e
bindig.pry
After you that you can check error class with e.class, to make sure you are catching good exception.
I am attempting to rescue RuntimeErrors from within my controller using rescue_from, log it as a HealthNotice, and then redirect the user with a flash message, but I'm finding that in certain circumstances, the rescue_from method is being run twice (I end up with 2 duplicate HealthNotices). If the exception is rasied from a function called in a method (such as the test method below), it only creates one, but if I raise the exception directly within the method (such as test2), the rescue function is running twice (although strangely I don't get a double render error -- ??)
class Portal::BluerimController < PortalController
rescue_from RuntimeError, with: :error_handler
def error_handler(e)
hn_long_message = "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}\n\nPARAMS:\n#{params}"
HealthNotice.create(name: "API Exception Handled", severity: "WARNING", short_message: e.message, long_message: hn_long_message)
flash[:notice] = e.message
redirect_to :action => :index and return
end
def test
Sotal.new.test # a method that raises a RuntimeError -- only 1 HealthNotice
end
def test2
raise "an error" # results in duplicate HealthNotice
end
end
Any suggestions on what I'm doing wrong? Thanks!
In my rails app, I have a transaction block in a controller's create action in which I attempt to create two records.
def create
ActiveRecord::Base.transaction do
#foo = Foo.new(params[:foo].except(:bar))
raise ActiveRecord::Rollback unless #foo.save
#bar = Bar.new(params[:foo][:bar])
raise ActiveRecord::Rollback unless #bar.save
end
end
I'd like to be able to rescue from the Rollback so I can return an error indicating which save failed.
rescue ActiveRecord::Rollback => e
#foo.errors = e if #foo.errors.blank?
ensure
respond_with #foo
end
However, I never get into the rescue block. I assume this is because, as the rails documentation states, the transaction block eats the Rollback exception and doesn't re-raise it. Is there a way to force this exception to be re-raised?