Reputation: 15702
In order to drastically reduce code repetition, I want to write up a concern with a generic way to add a special around_action
to a controller. It is basically supposed to catch any exception, render the right template and add the exception as a notice. However, it must be applicable to different actions, and show different templates depending on the action. My goal is basically to be able to do this:
protect_from_exception_with 'index', only: [ :update ]
In order to achieve this, I tried to write up my concern like this (Using Rails 4.1):
module CatchException
extend ActiveSupport::Concern
module ClassMethods
def protect_from_exception_with(failure_template, params)
around_action -> { catch_exception_with(failure_template) }, params
end
end
private
def log_error(e)
# Many things happen here
end
def catch_exception_with(failure_template)
yield
rescue => e
log_error(e)
render failure_template
end
end
However, this leads to an error:
LocalJumpError: no block given (yield)
I have trying to find examples for around_action
or around_filter
with a parameter, but could only find them for before_action
.
I hope what I'm trying to achieve is at all possible, otherwise I'd need to write a new method in every controller for every action I need to achieve this.
Upvotes: 1
Views: 1878
Reputation: 6707
There are some clues:
callback
and a block
as params, if we send a function
as the 1st param, that function
mustn't have any parameter!protect_from_exception_with
, I can call block_given?
, it returns true
, but I don't know how to get the block out! This works:
module CatchException
extend ActiveSupport::Concern
module ClassMethods
def protect_from_exception_with(failure_template, params)
around_action -> { catch_exception_with(failure_template) }, params
end
end
private
def log_error(e)
# Many things happen here
end
def catch_exception_with(failure_template)
self.send(params[:action])
rescue => e
log_error(e)
render failure_template
end
end
Thankfully, we still have the params in catch_exception_with
, make it easy, call the action back to the controller!
Upvotes: 3