rocket_pants 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/rocket_pants.rb +36 -1
- data/lib/rocket_pants/active_record.rb +19 -0
- data/lib/rocket_pants/base.rb +1 -1
- data/lib/rocket_pants/client.rb +1 -1
- data/lib/rocket_pants/controller/error_handling.rb +25 -7
- data/lib/rocket_pants/controller/rescuable.rb +2 -1
- data/lib/rocket_pants/error.rb +59 -0
- data/lib/rocket_pants/{exceptions.rb → errors.rb} +24 -55
- data/lib/rocket_pants/locale/en.yml +3 -1
- data/lib/rocket_pants/railtie.rb +15 -7
- metadata +4 -2
data/lib/rocket_pants.rb
CHANGED
@@ -7,7 +7,8 @@ require 'moneta'
|
|
7
7
|
require 'moneta/memory'
|
8
8
|
|
9
9
|
module RocketPants
|
10
|
-
require 'rocket_pants/
|
10
|
+
require 'rocket_pants/error'
|
11
|
+
require 'rocket_pants/errors'
|
11
12
|
|
12
13
|
# Set up the routing in advance.
|
13
14
|
require 'rocket_pants/routing'
|
@@ -39,6 +40,7 @@ module RocketPants
|
|
39
40
|
autoload :UrlFor, 'rocket_pants/controller/url_for'
|
40
41
|
|
41
42
|
mattr_accessor :caching_enabled, :header_metadata
|
43
|
+
|
42
44
|
self.caching_enabled = false
|
43
45
|
self.header_metadata = false
|
44
46
|
|
@@ -51,6 +53,39 @@ module RocketPants
|
|
51
53
|
def cache
|
52
54
|
@@cache ||= Moneta::Memory.new
|
53
55
|
end
|
56
|
+
|
57
|
+
def env
|
58
|
+
@@env ||= default_env
|
59
|
+
end
|
60
|
+
|
61
|
+
def env=(value)
|
62
|
+
value = value.presence && ActiveSupport::StringInquirer.new(value)
|
63
|
+
@@env = value
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_env
|
67
|
+
env = Rails.env.to_s if defined?(Rails.env)
|
68
|
+
env ||= ENV['RAILS_ENV'].presence || ENV['RACK_ENV'].presence || "development"
|
69
|
+
ActiveSupport::StringInquirer.new env
|
70
|
+
end
|
71
|
+
|
72
|
+
def default_pass_through_errors
|
73
|
+
env.development? || env.test?
|
74
|
+
end
|
75
|
+
|
76
|
+
def pass_through_errors
|
77
|
+
if defined?(@@pass_through_errors) && [true, false].include?(@@pass_through_errors)
|
78
|
+
@@pass_through_errors
|
79
|
+
else
|
80
|
+
@@pass_through_errors = default_pass_through_errors
|
81
|
+
end
|
82
|
+
end
|
83
|
+
alias pass_through_errors? pass_through_errors
|
84
|
+
|
85
|
+
def pass_through_errors=(value)
|
86
|
+
@@pass_through_errors = value
|
87
|
+
end
|
88
|
+
|
54
89
|
end
|
55
90
|
|
56
91
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Provides a bunch of default active record integration entry points.
|
2
|
+
module RocketPants
|
3
|
+
module ActiveRecordIntegration
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
map_error! ActiveRecord::RecordNotFound, RocketPants::NotFound
|
8
|
+
map_error!(ActiveRecord::RecordNotSaved) { RocketPants::InvalidResource.new nil }
|
9
|
+
map_error! ActiveRecord::RecordInvalid do |exception|
|
10
|
+
RocketPants::InvalidResource.new exception.record.errors
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
ActiveSupport.on_load :active_record do
|
15
|
+
RocketPants::Base.send :include, RocketPants::ActiveRecordIntegration
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/rocket_pants/base.rb
CHANGED
data/lib/rocket_pants/client.rb
CHANGED
@@ -2,7 +2,7 @@ require 'active_support/core_ext/class/attribute'
|
|
2
2
|
require 'active_support/core_ext/object/blank'
|
3
3
|
require 'active_support/core_ext/string/inflections'
|
4
4
|
|
5
|
-
require 'rocket_pants/
|
5
|
+
require 'rocket_pants/errors'
|
6
6
|
|
7
7
|
require 'api_smith'
|
8
8
|
require 'will_paginate/collection'
|
@@ -13,8 +13,15 @@ module RocketPants
|
|
13
13
|
|
14
14
|
module ClassMethods
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
# Declares that a given error class (e.g. ActiveRecord::RecordNotFound)
|
17
|
+
# should map to a second value - either an Exception class Or, more usefully,
|
18
|
+
# a callable object.
|
19
|
+
# @param [Class] from the exception class to map from.
|
20
|
+
# @param [Class, #call] to the callable to map to, or a callback block.
|
21
|
+
def map_error!(from, to = nil, &blk)
|
22
|
+
to = (to || blk)
|
23
|
+
raise ArgumentError, "Either an option must be provided or a block given." unless to
|
24
|
+
error_mapping[from] = (to || blk)
|
18
25
|
rescue_from from, :with => :render_error
|
19
26
|
end
|
20
27
|
|
@@ -47,7 +54,8 @@ module RocketPants
|
|
47
54
|
# TODO: Add in notification hooks for non-standard exceptions.
|
48
55
|
name = lookup_error_name(exception)
|
49
56
|
message = (exception.message == exception.class.name) ? 'An unknown error has occurred.' : exception.message
|
50
|
-
|
57
|
+
context = lookup_error_context(exception).reverse_merge(:scope => :"rocket_pants.errors", :default => message)
|
58
|
+
I18n.t name, context.except(:metadata)
|
51
59
|
end
|
52
60
|
|
53
61
|
# Lookup error name will automatically handle translating errors to a
|
@@ -77,12 +85,17 @@ module RocketPants
|
|
77
85
|
exception.respond_to?(:context) ? exception.context : {}
|
78
86
|
end
|
79
87
|
|
80
|
-
# Returns extra error details for a given object, making it useable
|
81
|
-
# for hooking in external exceptions.
|
82
88
|
def lookup_error_extras(exception)
|
83
89
|
{}
|
84
90
|
end
|
85
91
|
|
92
|
+
# Returns extra error details for a given object, making it useable
|
93
|
+
# for hooking in external exceptions.
|
94
|
+
def lookup_error_metadata(exception)
|
95
|
+
context = lookup_error_context exception
|
96
|
+
context.fetch(:metadata, {}).merge lookup_error_extras(exception)
|
97
|
+
end
|
98
|
+
|
86
99
|
# Renders an exception as JSON using a nicer version of the error name and
|
87
100
|
# error message, following the typically error standard as laid out in the JSON
|
88
101
|
# api design.
|
@@ -95,13 +108,18 @@ module RocketPants
|
|
95
108
|
klass < StandardError and error_mapping.has_key?(klass)
|
96
109
|
end
|
97
110
|
if normalised_class
|
98
|
-
|
111
|
+
mapped = error_mapping[normalised_class]
|
112
|
+
if mapped.respond_to?(:call)
|
113
|
+
exception = mapped.call(exception)
|
114
|
+
else
|
115
|
+
exception = mapped.new exception.message
|
116
|
+
end
|
99
117
|
end
|
100
118
|
self.status = lookup_error_status(exception)
|
101
119
|
render_json({
|
102
120
|
:error => lookup_error_name(exception).to_s,
|
103
121
|
:error_description => lookup_error_message(exception)
|
104
|
-
}.merge(
|
122
|
+
}.merge(lookup_error_metadata(exception)))
|
105
123
|
end
|
106
124
|
|
107
125
|
end
|
@@ -8,7 +8,7 @@ module RocketPants
|
|
8
8
|
include ActiveSupport::Rescuable
|
9
9
|
|
10
10
|
DEFAULT_NOTIFIER_CALLBACK = lambda do |controller, exception, req|
|
11
|
-
#
|
11
|
+
# Does nothing
|
12
12
|
end
|
13
13
|
|
14
14
|
NAMED_NOTIFIER_CALLBACKS = {
|
@@ -52,6 +52,7 @@ module RocketPants
|
|
52
52
|
def process_action(*args)
|
53
53
|
super
|
54
54
|
rescue Exception => exception
|
55
|
+
raise if RocketPants.pass_through_errors?
|
55
56
|
# Otherwise, use the default built in handler.
|
56
57
|
logger.error "Exception occured: #{exception.class.name} - #{exception.message}"
|
57
58
|
logger.error "Exception backtrace:"
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module RocketPants
|
2
|
+
|
3
|
+
# Represents the standard error type as defined by the API.
|
4
|
+
# RocketPants::Error instances will be caught and automatically rendered as JSON
|
5
|
+
# by the controller during processing.
|
6
|
+
class Error < StandardError
|
7
|
+
|
8
|
+
# @overload error_name
|
9
|
+
# Returns the error name for this error class, defaulting to
|
10
|
+
# the class name underscorized minus _error.
|
11
|
+
# @return [Symbol] the given errors name.
|
12
|
+
# @overload error_name(value)
|
13
|
+
# Sets the error name for the current class.
|
14
|
+
# @param [#to_sym] the name of this error.
|
15
|
+
def self.error_name(value = nil)
|
16
|
+
if value.nil?
|
17
|
+
@name ||= name.underscore.split("/").last.sub(/_error$/, '').to_sym
|
18
|
+
else
|
19
|
+
@name = (value.presence && value.to_sym)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @overload http_status
|
24
|
+
# Returns the http status code of this error, defaulting to 400 (Bad Request).
|
25
|
+
# @overload http_status(value)
|
26
|
+
# Sets the http status code for this error to a given symbol / integer.
|
27
|
+
# @param value [String, Fixnum] value the new status code.
|
28
|
+
def self.http_status(value = nil)
|
29
|
+
if value.nil?
|
30
|
+
@http_status ||= 400
|
31
|
+
else
|
32
|
+
@http_status = (value.presence && value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Gets the name of this error from the class.
|
37
|
+
def error_name
|
38
|
+
self.class.error_name
|
39
|
+
end
|
40
|
+
|
41
|
+
# Gets the http status of this error from the class.
|
42
|
+
def http_status
|
43
|
+
self.class.http_status
|
44
|
+
end
|
45
|
+
|
46
|
+
# Setter for optional data about this error, used for translation.
|
47
|
+
attr_writer :context
|
48
|
+
|
49
|
+
# Gets the context for this error, defaulting to nil.
|
50
|
+
# @return [Hash] the context for this param.
|
51
|
+
def context
|
52
|
+
@context ||= {}
|
53
|
+
end
|
54
|
+
|
55
|
+
error_name :unknown
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -1,60 +1,6 @@
|
|
1
1
|
module RocketPants
|
2
|
-
|
3
|
-
# Represents the standard error type as defined by the API.
|
4
|
-
# RocketPants::Error instances will be caught and automatically rendered as JSON
|
5
|
-
# by the controller during processing.
|
6
|
-
class Error < StandardError
|
7
|
-
|
8
|
-
# @overload error_name
|
9
|
-
# Returns the error name for this error class, defaulting to
|
10
|
-
# the class name underscorized minus _error.
|
11
|
-
# @return [Symbol] the given errors name.
|
12
|
-
# @overload error_name(value)
|
13
|
-
# Sets the error name for the current class.
|
14
|
-
# @param [#to_sym] the name of this error.
|
15
|
-
def self.error_name(value = nil)
|
16
|
-
if value.nil?
|
17
|
-
@name ||= name.underscore.split("/").last.sub(/_error$/, '').to_sym
|
18
|
-
else
|
19
|
-
@name = (value.presence && value.to_sym)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# @overload http_status
|
24
|
-
# Returns the http status code of this error, defaulting to 400 (Bad Request).
|
25
|
-
# @overload http_status(value)
|
26
|
-
# Sets the http status code for this error to a given symbol / integer.
|
27
|
-
# @param value [String, Fixnum] value the new status code.
|
28
|
-
def self.http_status(value = nil)
|
29
|
-
if value.nil?
|
30
|
-
@http_status ||= 400
|
31
|
-
else
|
32
|
-
@http_status = (value.presence && value)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Gets the name of this error from the class.
|
37
|
-
def error_name
|
38
|
-
self.class.error_name
|
39
|
-
end
|
40
|
-
|
41
|
-
# Gets the http status of this error from the class.
|
42
|
-
def http_status
|
43
|
-
self.class.http_status
|
44
|
-
end
|
45
|
-
|
46
|
-
# Setter for optional data about this error, used for translation.
|
47
|
-
attr_writer :context
|
48
|
-
|
49
|
-
# Gets the context for this error, defaulting to nil.
|
50
|
-
# @return [Hash] the context for this param.
|
51
|
-
def context
|
52
|
-
@context ||= {}
|
53
|
-
end
|
54
|
-
|
55
|
-
error_name :unknown
|
56
2
|
|
57
|
-
|
3
|
+
require 'rocket_pants/error'
|
58
4
|
|
59
5
|
# A simple map of data about errors that the rocket pants system can handle.
|
60
6
|
class Errors
|
@@ -111,5 +57,28 @@ module RocketPants
|
|
111
57
|
register! :bad_request, :http_status => :bad_request
|
112
58
|
|
113
59
|
end
|
60
|
+
|
61
|
+
class InvalidResource < RocketPants::Error
|
62
|
+
http_status :unprocessable_entity
|
63
|
+
error_name :invalid_resource
|
64
|
+
|
65
|
+
# Errors are ActiveModel Errors
|
66
|
+
attr_reader :errors
|
67
|
+
|
68
|
+
def initialize(errors, *args)
|
69
|
+
@errors = errors
|
70
|
+
super *args
|
71
|
+
end
|
72
|
+
|
73
|
+
def context
|
74
|
+
super.tap do |ctx|
|
75
|
+
extras = (ctx[:metadata] ||= {})
|
76
|
+
extras[:messages] = errors.to_hash if errors
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
Errors.add self
|
81
|
+
|
82
|
+
end
|
114
83
|
|
115
84
|
end
|
@@ -5,4 +5,6 @@ en:
|
|
5
5
|
unauthenticated: "This action requires authentication to continue."
|
6
6
|
invalid_version: "This action is not available in the given version of the api."
|
7
7
|
not_implemented: "The feature you requested has not yet been implemented and hence is currently unavailable."
|
8
|
-
not_found: "The requested resource could not be found."
|
8
|
+
not_found: "The requested resource could not be found."
|
9
|
+
bad_request: "The data given to this server does not meet our criteria."
|
10
|
+
invalid_resource: "The current resource was deemed invalid."
|
data/lib/rocket_pants/railtie.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module RocketPants
|
2
2
|
class Railtie < Rails::Railtie
|
3
3
|
|
4
|
-
config.rocket_pants
|
5
|
-
config.rocket_pants.use_caching
|
6
|
-
config.rocket_pants.header_metadata
|
4
|
+
config.rocket_pants = ActiveSupport::OrderedOptions.new
|
5
|
+
config.rocket_pants.use_caching = nil
|
6
|
+
config.rocket_pants.header_metadata = nil
|
7
|
+
config.rocket_pants.pass_through_errors = nil
|
7
8
|
|
8
9
|
config.i18n.railties_load_path << File.expand_path('../locale/en.yml', __FILE__)
|
9
10
|
|
@@ -12,10 +13,11 @@ module RocketPants
|
|
12
13
|
end
|
13
14
|
|
14
15
|
initializer "rocket_pants.configuration" do |app|
|
15
|
-
rp_config
|
16
|
-
rp_config.use_caching
|
17
|
-
RocketPants.caching_enabled
|
18
|
-
RocketPants.header_metadata
|
16
|
+
rp_config = app.config.rocket_pants
|
17
|
+
rp_config.use_caching = Rails.env.production? if rp_config.use_caching.nil?
|
18
|
+
RocketPants.caching_enabled = rp_config.use_caching
|
19
|
+
RocketPants.header_metadata = rp_config.header_metadata unless rp_config.header_metadata.nil?
|
20
|
+
RocketPants.pass_through_errors = rp_config.pass_through_errors unless rp_config.pass_through_errors.nil?
|
19
21
|
# Set the rocket pants cache if present.
|
20
22
|
RocketPants.cache = rp_config.cache if rp_config.cache
|
21
23
|
end
|
@@ -38,6 +40,12 @@ module RocketPants
|
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
43
|
+
initializer "rocket_pants.setup_activerecord" do
|
44
|
+
if defined?(ActiveRecord)
|
45
|
+
require 'rocket_pants/active_record'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
41
49
|
rake_tasks do
|
42
50
|
load "rocket_pants/tasks/rocket_pants.rake"
|
43
51
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rocket_pants
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -243,6 +243,7 @@ executables: []
|
|
243
243
|
extensions: []
|
244
244
|
extra_rdoc_files: []
|
245
245
|
files:
|
246
|
+
- lib/rocket_pants/active_record.rb
|
246
247
|
- lib/rocket_pants/base.rb
|
247
248
|
- lib/rocket_pants/cache_middleware.rb
|
248
249
|
- lib/rocket_pants/cacheable.rb
|
@@ -258,7 +259,8 @@ files:
|
|
258
259
|
- lib/rocket_pants/controller/respondable.rb
|
259
260
|
- lib/rocket_pants/controller/url_for.rb
|
260
261
|
- lib/rocket_pants/controller/versioning.rb
|
261
|
-
- lib/rocket_pants/
|
262
|
+
- lib/rocket_pants/error.rb
|
263
|
+
- lib/rocket_pants/errors.rb
|
262
264
|
- lib/rocket_pants/locale/en.yml
|
263
265
|
- lib/rocket_pants/railtie.rb
|
264
266
|
- lib/rocket_pants/routing.rb
|