Skip to content

Commit 4290154

Browse files
committed
Merge branch 'master' into rails5m
* master: Log errors captured by the JSON api Properly handle routing errors Pass through non-JSON api errors Broaden error detail environments Port the public exceptions injection Add wrapping of `ActiveRecord::RecordNotFound` Move class method and add module access control Fix 🐛 with message format Copy helpful comments about original source don't store a reference to the User class
2 parents ba3c3dd + 3ed6b30 commit 4290154

File tree

7 files changed

+101
-9
lines changed

7 files changed

+101
-9
lines changed

lib/kracken.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
require "kracken/credential_authenticator"
1010
require "kracken/authenticator"
1111
require "kracken/registration"
12+
require "kracken/railtie" if defined?(Rails)
1213

1314
module Kracken
1415
mattr_accessor :config

lib/kracken/config.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ class Config
33
attr_accessor :app_id, :app_secret
44
attr_writer :provider_url, :user_class
55

6+
def initialize
7+
@user_class = nil
8+
end
9+
610
def provider_url
711
@provider_url ||= PROVIDER_URL
812
end
913

1014
def user_class
11-
@user_class ||= ::User
15+
@user_class || ::User
1216
end
1317
end
1418
end

lib/kracken/controllers/json_api_compatible.rb

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ module Kracken
22
module Controllers
33
module JsonApiCompatible
44

5-
65
module MungeAndMirror
76
# Wraps the data root in an Array, if it is not already an Array. This
87
# will not wrap the value if the resource root is not present.
@@ -122,7 +121,29 @@ def resource_type
122121
end
123122
include VirtualAttributes
124123

124+
def self.included(base)
125+
base.instance_exec do
126+
extend Macros
127+
128+
before_action :munge_chained_param_ids!
129+
skip_before_action :verify_authenticity_token
130+
131+
if defined?(::ActiveRecord)
132+
rescue_from ::ActiveRecord::RecordNotFound do |error|
133+
# In order to use named captures we need to use an inline regex
134+
# on the LHS.
135+
#
136+
# Source: http://rubular.com/r/NoQ4SZMav4
137+
/Couldn't find( all)? (?<resource>\w+) with 'id'.?( \()?(?<ids>[,\s\w]+)\)?/ =~ error.message
138+
resource = resource.underscore.pluralize
139+
raise ResourceNotFound.new(resource, ids.strip)
140+
end
141+
end
142+
end
143+
end
144+
125145
# Common Actions Necessary in JSON API controllers
146+
module_function
126147

127148
# Wrap a block in an Active Record transaction
128149
#

lib/kracken/controllers/token_authenticatable.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ def self.included(base)
1313
end
1414
end
1515

16+
# Customize the `authenticate_or_request_with_http_token` process:
17+
# http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token/ControllerMethods.html#method-i-request_http_token_authentication
18+
#
19+
# Modified from https://github.com/rails/rails/blob/60d0aec7/actionpack/lib/action_controller/metal/http_authentication.rb#L490-L499
1620
if Rails::VERSION::MAJOR >= 5
1721
def request_http_token_authentication(realm = 'Application', message = nil)
1822
headers["WWW-Authenticate"] = %(Token realm="#{realm.gsub(/"/, "")}")

lib/kracken/error.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def initialize(resource, missing_ids)
1717
@missing_ids = Array(missing_ids)
1818
@resource = resource
1919
super(
20-
"Couldn't find #{resource} with id(s): #{missing_ids.join(', ')}"
20+
"Couldn't find #{@resource} with id(s): #{@missing_ids.join(', ')}"
2121
)
2222
end
2323
end

lib/kracken/json_api/public_exceptions.rb

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,67 @@
11
module Kracken
22
module JsonApi
3+
# Error logging methods used by `ActionDispatch::DebugExceptions`
4+
# https://github.com/rails/rails/blob/v4.2.6/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
5+
module ErrorLogging
6+
def log_error(env, wrapper)
7+
logger = logger(env)
8+
return unless logger
9+
10+
exception = wrapper.exception
11+
12+
trace = wrapper.application_trace
13+
trace = wrapper.framework_trace if trace.empty?
14+
15+
ActiveSupport::Deprecation.silence do
16+
message = "\n#{exception.class} (#{exception.message}):\n"
17+
message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
18+
message << " " << trace.join("\n ")
19+
logger.fatal("#{message}\n\n")
20+
end
21+
end
22+
23+
def logger(env)
24+
env['action_dispatch.logger'] || stderr_logger
25+
end
26+
27+
def stderr_logger
28+
@stderr_logger ||= ActiveSupport::Logger.new($stderr)
29+
end
30+
end
31+
332
class PublicExceptions
4-
attr_reader :app
33+
include ErrorLogging
34+
535
def initialize(app)
636
@app = app
737
end
838

939
def call(env)
10-
app.call(env)
40+
if JsonApi.has_path?(JsonApi::Request.new(env))
41+
capture_error(env)
42+
else
43+
@app.call(env)
44+
end
45+
end
46+
47+
# Use similar logic to how `ActionDispatch::DebugExceptions` captures
48+
# routing errors.
49+
# https://github.com/rails/rails/blob/v4.2.6/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
50+
def capture_error(env)
51+
_, headers, body = response = @app.call(env)
52+
53+
if headers['X-Cascade'] == 'pass'
54+
body.close if body.respond_to?(:close)
55+
raise ActionController::RoutingError,
56+
"No route matches [#{env['REQUEST_METHOD']}] " \
57+
"#{env['PATH_INFO'].inspect}"
58+
end
59+
60+
response
1161
rescue Exception => exception
12-
raise exception unless JsonApi.has_path?(JsonApi::Request.new(env))
13-
render_json_error(ExceptionWrapper.new(env, exception))
62+
wrapper = ExceptionWrapper.new(env, exception)
63+
log_error(env, wrapper)
64+
render_json_error(wrapper)
1465
end
1566

1667
if Rails.env.production?
@@ -27,8 +78,8 @@ def additional_details(error)
2778

2879
def show_error_details?(wrapper)
2980
wrapper.is_details_exception? ||
30-
( Rails.application.config.consider_all_requests_local &&
31-
wrapper.status_code == 500)
81+
Rails.application.config.consider_all_requests_local ||
82+
(Rails.env.test? && wrapper.status_code == 500)
3283
end
3384

3485
def error_as_json(wrapper)

lib/kracken/railtie.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
require "kracken/json_api"
2+
3+
module Kracken
4+
# Railtie to hook into Rails.
5+
class Railtie < ::Rails::Railtie
6+
initializer "kracken.json_api.public_exceptions" do |app|
7+
app.middleware.insert_after ActionDispatch::DebugExceptions,
8+
::Kracken::JsonApi::PublicExceptions
9+
end
10+
end
11+
end

0 commit comments

Comments
 (0)