Skip to content

Commit 4c856ef

Browse files
committed
call server_error_callbacks on handle_exceptions in controller
1 parent 3b1d574 commit 4c856ef

3 files changed

Lines changed: 73 additions & 24 deletions

File tree

lib/jsonapi/acts_as_resource_controller.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,13 +266,27 @@ def handle_exceptions(e)
266266
if JSONAPI.configuration.exception_class_whitelisted?(e)
267267
fail e
268268
else
269+
(self.class.server_error_callbacks || []).each { |callback|
270+
safe_run_callback(callback, e)
271+
}
272+
269273
internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e)
270274
Rails.logger.error { "Internal Server Error: #{e.message} #{e.backtrace.join("\n")}" }
271275
render_errors(internal_server_error.errors)
272276
end
273277
end
274278
end
275279

280+
def safe_run_callback(callback, error)
281+
begin
282+
callback.call(error)
283+
rescue => e
284+
Rails.logger.error { "Error in error handling callback: #{e.message} #{e.backtrace.join("\n")}" }
285+
internal_server_error = JSONAPI::Exceptions::InternalServerError.new(e)
286+
render_errors(internal_server_error.errors)
287+
end
288+
end
289+
276290
# Pass in a methods or a block to be run when an exception is
277291
# caught that is not a JSONAPI::Exceptions::Error
278292
# Useful for additional logging or notification configuration that

test/controllers/controller_test.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,26 @@ def test_on_server_error_method_callback_with_exception
123123
JSONAPI.configuration = original_config
124124
end
125125

126+
def test_on_server_error_method_callback_with_exception_on_serialize
127+
original_config = JSONAPI.configuration.dup
128+
JSONAPI.configuration.exception_class_whitelist = []
129+
$PostSerializerRaisesErrors = true
130+
131+
#ignores methods that don't exist
132+
@controller.class.on_server_error :set_callback_message, :a_bogus_method
133+
@controller.class.instance_variable_set(:@callback_message, "none")
134+
135+
assert_cacheable_get :index
136+
assert_equal "Sent from method", @controller.class.instance_variable_get(:@callback_message)
137+
138+
# test that it renders the default server error response
139+
assert_equal "Internal Server Error", json_response['errors'][0]['title']
140+
ensure
141+
$PostSerializerRaisesErrors = false
142+
JSONAPI.configuration = original_config
143+
JSONAPI.configuration.exception_class_whitelist = []
144+
end
145+
126146
def test_on_server_error_callback_without_exception
127147

128148
callback = Proc.new { @controller.class.instance_variable_set(:@callback_message, "Sent from block") }

test/fixtures/active_record.rb

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ class PostsController < BaseController
580580

581581
class SpecialError < StandardError; end
582582
class SubSpecialError < PostsController::SpecialError; end
583+
class SerializeError < StandardError; end
583584

584585
# This is used to test that classes that are whitelisted are reraised by
585586
# the operations dispatcher.
@@ -600,6 +601,20 @@ def handle_exceptions(e)
600601
def self.set_callback_message(error)
601602
@callback_message = "Sent from method"
602603
end
604+
605+
def resource_serializer_klass
606+
PostSerializer
607+
end
608+
end
609+
610+
class PostSerializer < JSONAPI::ResourceSerializer
611+
def initialize(*)
612+
if $PostSerializerRaisesErrors
613+
raise PostsController::SerializeError
614+
else
615+
super
616+
end
617+
end
603618
end
604619

605620
class CommentsController < JSONAPI::ResourceController
@@ -980,12 +995,12 @@ def title=(title)
980995
}
981996

982997
filter :search,
983-
verify: ->(values, context) {
998+
verify: ->(values, context) {
984999
values.all?{|v| (v.is_a?(Hash) || v.is_a?(ActionController::Parameters)) } && values
985-
},
986-
apply: -> (records, values, _options) {
987-
records.where(title: values.first['title'])
988-
}
1000+
},
1001+
apply: -> (records, values, _options) {
1002+
records.where(title: values.first['title'])
1003+
}
9891004

9901005
def self.updatable_fields(context)
9911006
super(context) - [:author, :subject]
@@ -1252,7 +1267,7 @@ def subject
12521267

12531268
def custom_links(options)
12541269
{
1255-
link_to_external_api: "http://external-api.com/posts/#{ created_at.year }/#{ created_at.month }/#{ created_at.day }-#{ subject.gsub(' ', '-') }"
1270+
link_to_external_api: "http://external-api.com/posts/#{ created_at.year }/#{ created_at.month }/#{ created_at.day }-#{ subject.gsub(' ', '-') }"
12561271
}
12571272
end
12581273
end
@@ -1513,28 +1528,28 @@ class PurchaseOrderResource < JSONAPI::Resource
15131528

15141529
has_one :customer
15151530
has_many :line_items, relation_name: -> (options = {}) {
1516-
context = options[:context]
1517-
current_user = context ? context[:current_user] : nil
1518-
1519-
unless current_user && current_user.book_admin
1520-
:line_items
1521-
else
1522-
:admin_line_items
1523-
end
1524-
},
1531+
context = options[:context]
1532+
current_user = context ? context[:current_user] : nil
1533+
1534+
unless current_user && current_user.book_admin
1535+
:line_items
1536+
else
1537+
:admin_line_items
1538+
end
1539+
},
15251540
reflect: false
15261541

15271542
has_many :order_flags, acts_as_set: true,
15281543
relation_name: -> (options = {}) {
1529-
context = options[:context]
1530-
current_user = context ? context[:current_user] : nil
1531-
1532-
unless current_user && current_user.book_admin
1533-
:order_flags
1534-
else
1535-
:admin_order_flags
1536-
end
1537-
}
1544+
context = options[:context]
1545+
current_user = context ? context[:current_user] : nil
1546+
1547+
unless current_user && current_user.book_admin
1548+
:order_flags
1549+
else
1550+
:admin_order_flags
1551+
end
1552+
}
15381553
end
15391554

15401555
class OrderFlagResource < JSONAPI::Resource

0 commit comments

Comments
 (0)