Skip to content

Commit

Permalink
fix(ruby-grape#1922): Allow to use instance variables defined in the …
Browse files Browse the repository at this point in the history
…endpoints when rescue_from
  • Loading branch information
jcagarcia committed Nov 21, 2023
1 parent 3f01d03 commit a77be51
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 4 deletions.
17 changes: 17 additions & 0 deletions lib/grape/dsl/inside_route.rb
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,23 @@ def error!(message, status = nil, additional_headers = nil)
throw :error, message: message, status: self.status, headers: headers
end

# Creates a Rack response based on the provided message, status, and headers.
# The content type in the headers is set to the default content type unless provided.
# The message is HTML-escaped if the content type is 'text/html'.
#
# @param message [String] The content of the response.
# @param status [Integer] The HTTP status code.
# @params headers [Hash] (optional) Headers for the response
# (default: {Rack::CONTENT_TYPE => content_type}).
#
# Returns:
# A Rack::Response object containing the specified message, status, and headers.
#
def rack_response(message, status, headers = { Rack::CONTENT_TYPE => content_type })
message = ERB::Util.html_escape(message) if headers[Rack::CONTENT_TYPE] == 'text/html'
Rack::Response.new([message], Rack::Utils.status_code(status), headers)
end

# Redirect to a new url.
#
# @param url [String] The url to be redirect.
Expand Down
18 changes: 14 additions & 4 deletions lib/grape/middleware/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def call!(env)
rescue_handler_for_any_class(e.class) ||
raise

run_rescue_handler(handler, e)
run_rescue_handler(@env[Grape::Env::API_ENDPOINT], handler, e)
end
end

Expand Down Expand Up @@ -119,21 +119,31 @@ def rescue_handler_for_any_class(klass)
options[:all_rescue_handler] || :default_rescue_handler
end

def run_rescue_handler(handler, error)
def run_rescue_handler(endpoint, handler, error)
if handler.instance_of?(Symbol)
raise NoMethodError, "undefined method '#{handler}'" unless respond_to?(handler)

handler = public_method(handler)
end

response = handler.arity.zero? ? instance_exec(&handler) : instance_exec(error, &handler)
response = (catch(:error) do
handler.arity.zero? ? endpoint.instance_exec(&handler) : endpoint.instance_exec(error, &handler)
end)

if error?(response)
response = error!(response[:message], response[:status], response[:headers])
end

if response.is_a?(Rack::Response)
response
else
run_rescue_handler(:default_rescue_handler, Grape::Exceptions::InvalidResponse.new)
run_rescue_handler(endpoint, :default_rescue_handler, Grape::Exceptions::InvalidResponse.new)
end
end

def error?(response)
response && response.is_a?(Hash) && response[:message] && response[:status] && response[:headers]
end
end
end
end
19 changes: 19 additions & 0 deletions spec/grape/api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2130,6 +2130,25 @@ class CustomError < Grape::Exceptions::Base; end
expect(last_response.status).to be 500
expect(last_response.body).to eql 'Invalid response'
end

context 'when using instance variables inside the rescue_from' do
it 'is able to access the values' do
expected_instance_variable_value = 'wadus'

subject.rescue_from(:all) do
body = { my_var: @my_var }
error!(body, 400)
end
subject.get('/') do
@my_var = expected_instance_variable_value
raise
end

get '/'
expect(last_response.status).to be 400
expect(last_response.body).to eq({ my_var: expected_instance_variable_value }.to_json)
end
end
end

describe '.rescue_from klass, block' do
Expand Down

0 comments on commit a77be51

Please sign in to comment.