human_error 1.13.4 → 2.0.0beta2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4ec632d4d98534bf56ffb31036e08757bc571329
4
- data.tar.gz: 0ccf6401fb434ed5439bd950cea70e19538c25a5
3
+ metadata.gz: 38bd2094b46916777e66209fd09752aec12782c6
4
+ data.tar.gz: 5e8539f5cf3898079f28f3a6014aca66f7d09d79
5
5
  SHA512:
6
- metadata.gz: 659545cf72c6db3d1cea151d9516d00c5c6c4d9e27bde9403cf352dfda4591a838476cb435f81344d5525ba8436032969a329c24cbfd7db95ad93b582dc25d9c
7
- data.tar.gz: 9f54d8085cdf37151658b1ac6112b4c5b2da2057f8707251443ea29f9525d889b415247dcbf738ec954840bd1b3842a7061a4cd0efba0e62273a535307026fdb
6
+ metadata.gz: 7395626c161f3012d42c7cf0de4d934bf77cf34447bb192d4b06f004efc80e11dfbd6f910cb7b1efb4a5c53759f4a114e5f535242d32073a3e2714eb83cea386
7
+ data.tar.gz: b1dbf433d0e8725ef3ac2192dc2bb6afc8e3bc49078eb43fd5309334959d0ac76b58fa41f1b9426189309304c4ca391686c32d9a62ea207f2654c9c51a74aa50
@@ -10,6 +10,25 @@ class AssociationError < RequestError
10
10
  :association_id,
11
11
  :attributes
12
12
 
13
+ def self.convert(original_error, overrides = {})
14
+ initialization_parameters = {}
15
+
16
+ case original_error.class.name
17
+ when 'ActiveRecord::InvalidForeignKey'
18
+ message_info_pattern = /DETAIL: Key \((.*)_id\)=\(([a-f0-9\-]+)\)/
19
+ message_info = original_error.
20
+ message.
21
+ match(message_info_pattern)[1..-1]
22
+
23
+ initialization_parameters = {
24
+ association_name: message_info[0],
25
+ association_id: message_info[1],
26
+ }
27
+ end
28
+
29
+ new(initialization_parameters.merge(overrides))
30
+ end
31
+
13
32
  def http_status
14
33
  422
15
34
  end
@@ -6,6 +6,26 @@ module Errors
6
6
  class ResourceNotFoundError < RequestError
7
7
  include CrudError
8
8
 
9
+ def self.convert(original_error, overrides = {})
10
+ initialization_parameters = {}
11
+
12
+ case original_error.class.name
13
+ when 'ActiveRecord::RecordNotFound'
14
+ initialization_parameters = {
15
+ resource_id: case original_error.message
16
+ when /\ACouldn't find .* without an ID\z/
17
+ []
18
+ when /\ACouldn't find .* with \'.*\'=([a-f0-9\-]+)/
19
+ [Regexp.last_match(1)]
20
+ when /\ACouldn't find all .* with \'.*\': ((?:[a-f0-9\-]+(?:, )?)+)/
21
+ Array(Regexp.last_match(1).split(', '))
22
+ end,
23
+ }
24
+ end
25
+
26
+ new(initialization_parameters.merge(overrides))
27
+ end
28
+
9
29
  def http_status
10
30
  404
11
31
  end
@@ -9,6 +9,22 @@ class ResourcePersistenceError < RequestError
9
9
  attr_accessor :errors,
10
10
  :attributes
11
11
 
12
+ def self.convert(original_error, overrides = {})
13
+ initialization_parameters = {}
14
+
15
+ case original_error.class.name
16
+ when 'ActiveRecord::RecordInvalid',
17
+ 'ActiveRecord::RecordNotSaved'
18
+
19
+ initialization_parameters = {
20
+ attributes: original_error.record.attributes,
21
+ errors: original_error.record.errors.full_messages,
22
+ }
23
+ end
24
+
25
+ new(initialization_parameters.merge(overrides))
26
+ end
27
+
12
28
  def http_status
13
29
  422
14
30
  end
@@ -6,49 +6,41 @@ class HumanError
6
6
  module RescuableResource
7
7
  module ClassMethods
8
8
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Style/GuardClause
9
- def rescue_resource(_resource_name, from:, via:)
10
- lookup_library = via
9
+ def rescue_resource(resource_name, from:, via:)
10
+ resource_class_name = resource_name.classify
11
+ lookup_library = via
11
12
 
12
13
  if from.include? 'persistence'
13
- rescue_from HumanError::Errors::ResourcePersistenceError do |e|
14
- error = lookup_library.fetch(
15
- 'ResourcePersistenceError',
16
- resource_name: e.resource_name,
17
- attributes: e.attributes,
18
- errors: e.errors,
19
- action: action_name)
20
-
21
- render json: error,
22
- status: error.http_status
14
+ rescue_from 'ActiveRecord::RecordInvalid',
15
+ 'ActiveRecord::RecordNotSaved' do |exception|
16
+ human_error = lookup_library.convert(exception,
17
+ resource_name: resource_class_name,
18
+ action: action_name)
19
+
20
+ render json: human_error,
21
+ status: human_error.http_status
23
22
  end
24
23
  end
25
24
 
26
25
  if from.include? 'not_found'
27
- rescue_from HumanError::Errors::ResourceNotFoundError do |e|
28
- resource_id = e.resource_id.is_a?(Array) ? e.resource_id : [e.resource_id]
26
+ rescue_from 'ActiveRecord::RecordNotFound' do |exception|
27
+ human_error = lookup_library.convert(exception,
28
+ resource_name: resource_class_name,
29
+ action: action_name)
29
30
 
30
- error = lookup_library.fetch(
31
- 'ResourceNotFoundError',
32
- resource_name: e.resource_name,
33
- resource_id: resource_id,
34
- action: action_name)
35
-
36
- render json: error,
37
- status: error.http_status
31
+ render json: human_error,
32
+ status: human_error.http_status
38
33
  end
39
34
  end
40
35
 
41
36
  if from.include? 'association'
42
- rescue_from HumanError::Errors::AssociationError do |e|
43
- error = lookup_library.fetch(
44
- 'AssociationError',
45
- resource_name: e.resource_name,
46
- association_name: e.association_name,
47
- association_id: e.association_id,
48
- attributes: e.attributes)
49
-
50
- render json: error,
51
- status: error.http_status
37
+ rescue_from 'ActiveRecord::InvalidForeignKey' do |exception|
38
+ human_error = lookup_library.convert(exception,
39
+ resource_name: resource_class_name,
40
+ action: action_name)
41
+
42
+ render json: human_error,
43
+ status: human_error.http_status
52
44
  end
53
45
  end
54
46
  end
@@ -1,3 +1,3 @@
1
1
  class HumanError
2
- VERSION = '1.13.4'
2
+ VERSION = '2.0.0beta2'
3
3
  end
data/lib/human_error.rb CHANGED
@@ -11,9 +11,19 @@ class HumanError
11
11
  yield configuration if block_given?
12
12
  end
13
13
 
14
- def fetch(error_type, **args)
15
- Object.const_get("HumanError::Errors::#{error_type}").
16
- new(configuration.to_h.merge(**args))
14
+ def fetch(error_type, **_args)
15
+ Object.const_get("HumanError::Errors::#{error_type}")
16
+ end
17
+
18
+ def convert(original_error, overrides = {})
19
+ overrides = configuration.to_h.merge(overrides)
20
+
21
+ case original_error.class.name
22
+ when 'ActiveRecord::InvalidForeignKey'
23
+ fetch('AssociationError').convert(original_error, overrides)
24
+ when 'ActiveRecord::RecordNotFound'
25
+ fetch('ResourceNotFoundError').convert(original_error, overrides)
26
+ end
17
27
  end
18
28
 
19
29
  def raise(error_type, **args)
@@ -1,20 +1,29 @@
1
1
  require 'rspectacular'
2
2
  require 'human_error/errors/crud_errors/association_error'
3
+ require 'active_record/errors'
3
4
 
4
5
  class HumanError
5
6
  module Errors
6
7
  describe AssociationError do
7
- let(:error) { AssociationError.new }
8
+ let(:foreign_key_error) do
9
+ ActiveRecord::InvalidForeignKey.new('DETAIL: Key (resource_id)=(123)')
10
+ end
8
11
 
9
12
  it 'has a status of 422' do
13
+ error = AssociationError.new
14
+
10
15
  expect(error.http_status).to eql 422
11
16
  end
12
17
 
13
18
  it 'has a code of 1009' do
19
+ error = AssociationError.new
20
+
14
21
  expect(error.code).to eql 1009
15
22
  end
16
23
 
17
24
  it 'has a knowledgebase article ID of 1234567890' do
25
+ error = AssociationError.new
26
+
18
27
  expect(error.knowledgebase_article_id).to eql '1234567890'
19
28
  end
20
29
 
@@ -46,6 +55,22 @@ describe AssociationError do
46
55
  expect(error.friendly_message).to eql 'Sorry! There was a problem when we tried to ' \
47
56
  'set the black leather trenchcoat on that Neo.'
48
57
  end
58
+
59
+ it 'can convert an "ActiveRecord::InvalidForeignKey"' do
60
+ error = AssociationError.convert(foreign_key_error)
61
+
62
+ expect(error.resource_name).to eql nil
63
+ expect(error.association_name).to eql 'resource'
64
+ expect(error.association_id).to eql '123'
65
+ end
66
+
67
+ it 'can convert an "ActiveRecord::InvalidForeignKey" while overriding attributes' do
68
+ error = AssociationError.convert(foreign_key_error, resource_name: 'my_resource')
69
+
70
+ expect(error.resource_name).to eql 'my_resource'
71
+ expect(error.association_name).to eql 'resource'
72
+ expect(error.association_id).to eql '123'
73
+ end
49
74
  end
50
75
  end
51
76
  end
@@ -1,20 +1,25 @@
1
1
  require 'rspectacular'
2
2
  require 'human_error/errors/crud_errors/resource_not_found_error'
3
+ require 'active_record/errors'
3
4
 
4
5
  class HumanError
5
6
  module Errors
6
7
  describe ResourceNotFoundError do
7
- let(:error) { ResourceNotFoundError.new }
8
-
9
8
  it 'has a status of 404' do
9
+ error = ResourceNotFoundError.new
10
+
10
11
  expect(error.http_status).to eql 404
11
12
  end
12
13
 
13
14
  it 'has a code of 1005' do
15
+ error = ResourceNotFoundError.new
16
+
14
17
  expect(error.code).to eql 1005
15
18
  end
16
19
 
17
20
  it 'has a knowledgebase article ID of 1234567890' do
21
+ error = ResourceNotFoundError.new
22
+
18
23
  expect(error.knowledgebase_article_id).to eql '1234567890'
19
24
  end
20
25
 
@@ -49,6 +54,43 @@ describe ResourceNotFoundError do
49
54
  expect(error.friendly_message).to eql 'Sorry! The black leather trenchcoat you ' \
50
55
  'tried to bullet time does not exist.'
51
56
  end
57
+
58
+ it 'can convert an "ActiveRecord::RecordNotFound" with no IDs' do
59
+ record_not_found_error = ActiveRecord::RecordNotFound.new \
60
+ "Couldn't find resource without an ID"
61
+ error = ResourceNotFoundError.convert(record_not_found_error)
62
+
63
+ expect(error.resource_name).to eql nil
64
+ expect(error.resource_id).to eql []
65
+ end
66
+
67
+ it 'can convert an "ActiveRecord::RecordNotFound" with one ID' do
68
+ record_not_found_error = ActiveRecord::RecordNotFound.new \
69
+ "Couldn't find resource with 'id'=123"
70
+ error = ResourceNotFoundError.convert(record_not_found_error)
71
+
72
+ expect(error.resource_name).to eql nil
73
+ expect(error.resource_id).to eql %w{123}
74
+ end
75
+
76
+ it 'can convert an "ActiveRecord::RecordNotFound" with multiple IDs' do
77
+ record_not_found_error = ActiveRecord::RecordNotFound.new \
78
+ "Couldn't find all resource with 'id': 123, 456, 789"
79
+ error = ResourceNotFoundError.convert(record_not_found_error)
80
+
81
+ expect(error.resource_name).to eql nil
82
+ expect(error.resource_id).to eql %w{123 456 789}
83
+ end
84
+
85
+ it 'can convert an "ActiveRecord::RecordNotFound" while overriding attributes' do
86
+ record_not_found_error = ActiveRecord::RecordNotFound.new \
87
+ "Couldn't find resource with 'id'=123"
88
+ error = ResourceNotFoundError.convert(record_not_found_error,
89
+ resource_name: 'my_resource')
90
+
91
+ expect(error.resource_name).to eql 'my_resource'
92
+ expect(error.resource_id).to eql %w{123}
93
+ end
52
94
  end
53
95
  end
54
96
  end
@@ -1,20 +1,43 @@
1
1
  require 'rspectacular'
2
2
  require 'human_error/errors/crud_errors/resource_persistence_error'
3
+ require 'active_support'
4
+ require 'active_model'
5
+ require 'active_record/errors'
6
+ require 'active_record/validations'
7
+
8
+ class HumanErrorTestModel
9
+ include ActiveModel::Model
10
+ include ActiveModel::AttributeMethods
11
+
12
+ attr_accessor :some_attribute
13
+
14
+ validates_presence_of :some_attribute
15
+
16
+ def attributes
17
+ {
18
+ 'some_attribute' => @some_attribute,
19
+ }
20
+ end
21
+ end
3
22
 
4
23
  class HumanError
5
24
  module Errors
6
25
  describe ResourcePersistenceError do
7
- let(:error) { ResourcePersistenceError.new }
8
-
9
26
  it 'has a status of 422' do
27
+ error = ResourcePersistenceError.new
28
+
10
29
  expect(error.http_status).to eql 422
11
30
  end
12
31
 
13
32
  it 'has a code of 1006' do
33
+ error = ResourcePersistenceError.new
34
+
14
35
  expect(error.code).to eql 1006
15
36
  end
16
37
 
17
38
  it 'has a knowledgebase article ID of 1234567890' do
39
+ error = ResourcePersistenceError.new
40
+
18
41
  expect(error.knowledgebase_article_id).to eql '1234567890'
19
42
  end
20
43
 
@@ -42,6 +65,28 @@ describe ResourcePersistenceError do
42
65
  expect(error.friendly_message).to eql 'Sorry! We had a problem when tried to ' \
43
66
  'bullet time that black leather trenchcoat.'
44
67
  end
68
+
69
+ it 'can convert an "ActiveRecord::RecordNotSaved"' do
70
+ record = HumanErrorTestModel.new
71
+ record.valid?
72
+ resource_persistence_error = ActiveRecord::RecordNotSaved.new('message', record)
73
+ error = ResourcePersistenceError.
74
+ convert(resource_persistence_error)
75
+
76
+ expect(error.attributes).to eql('some_attribute' => nil)
77
+ expect(error.errors).to eql ["Some attribute can't be blank"]
78
+ end
79
+
80
+ it 'can convert an "ActiveRecord::RecordInvalid"' do
81
+ record = HumanErrorTestModel.new
82
+ record.valid?
83
+ resource_persistence_error = ActiveRecord::RecordInvalid.new(record)
84
+ error = ResourcePersistenceError.
85
+ convert(resource_persistence_error)
86
+
87
+ expect(error.attributes).to eql('some_attribute' => nil)
88
+ expect(error.errors).to eql ["Some attribute can't be blank"]
89
+ end
45
90
  end
46
91
  end
47
92
  end
@@ -1,7 +1,12 @@
1
1
  require 'rspectacular'
2
2
  require 'human_error'
3
+ require 'active_record/errors'
3
4
 
4
5
  describe HumanError do
6
+ let(:original_error) do
7
+ ActiveRecord::RecordNotFound.new("Couldn't find resource with 'id'=3")
8
+ end
9
+
5
10
  it 'can create an instance of HumanError' do
6
11
  expect(HumanError.new).to be_a HumanError
7
12
  end
@@ -17,7 +22,7 @@ describe HumanError do
17
22
  it 'can lookup errors' do
18
23
  human_error = HumanError.new
19
24
 
20
- expect(human_error.fetch('RequestError')).to be_a HumanError::Errors::RequestError
25
+ expect(human_error.fetch('RequestError')).to eql HumanError::Errors::RequestError
21
26
  end
22
27
 
23
28
  it 'can lookup errors based on the local configuration' do
@@ -25,7 +30,7 @@ describe HumanError do
25
30
  config.api_version = 'foo'
26
31
  end
27
32
 
28
- fetched_error = human_error.fetch('RequestError')
33
+ fetched_error = human_error.convert(original_error)
29
34
 
30
35
  expect(fetched_error.api_version).to eql 'foo'
31
36
  end
@@ -41,7 +46,7 @@ describe HumanError do
41
46
  config.api_version = 'foo'
42
47
  end
43
48
 
44
- fetched_error = human_error.fetch('RequestError')
49
+ fetched_error = human_error.convert(original_error)
45
50
 
46
51
  expect(fetched_error.api_version).to eql 'foo'
47
52
  end
@@ -53,7 +58,7 @@ describe HumanError do
53
58
  config.api_version = 'foo'
54
59
  end
55
60
 
56
- fetched_error = human_error.fetch('RequestError', api_version: 'bar')
61
+ fetched_error = human_error.convert(original_error, api_version: 'bar')
57
62
 
58
63
  expect(fetched_error.api_version).to eql 'bar'
59
64
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: human_error
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.13.4
4
+ version: 2.0.0beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - jfelchner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-26 00:00:00.000000000 Z
11
+ date: 2015-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -39,19 +39,19 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.50'
41
41
  - !ruby/object:Gem::Dependency
42
- name: codeclimate-test-reporter
42
+ name: activerecord
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.3.0
47
+ version: '4.1'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.3.0
54
+ version: '4.1'
55
55
  description: ''
56
56
  email: accounts+git@thekompanee.com
57
57
  executables: []
@@ -76,7 +76,6 @@ files:
76
76
  - lib/human_error/errors/crud_errors/resource_persistence_error.rb
77
77
  - lib/human_error/errors/request_error.rb
78
78
  - lib/human_error/knowledgebase_id_directory.rb
79
- - lib/human_error/persistable.rb
80
79
  - lib/human_error/rescuable_resource.rb
81
80
  - lib/human_error/utilities/string.rb
82
81
  - lib/human_error/version.rb
@@ -106,9 +105,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
106
105
  version: '0'
107
106
  required_rubygems_version: !ruby/object:Gem::Requirement
108
107
  requirements:
109
- - - ">="
108
+ - - ">"
110
109
  - !ruby/object:Gem::Version
111
- version: '0'
110
+ version: 1.3.1
112
111
  requirements: []
113
112
  rubyforge_project:
114
113
  rubygems_version: 2.4.6
@@ -1,56 +0,0 @@
1
- class HumanError
2
- module Persistable
3
- module ClassMethods
4
- def find(*ids)
5
- super
6
- rescue ActiveRecord::RecordNotFound => e
7
- ids = case e.message
8
- when /\ACouldn't find .* without an ID\z/
9
- []
10
- when /\ACouldn't find .* with \'.*\'=([a-f0-9\-]+)/
11
- [Regexp.last_match(1)]
12
- when /\ACouldn't find all .* with \'.*\': ((?:[a-f0-9\-]+(?:, )?)+)/
13
- Regexp.last_match(1).split(', ')
14
- end
15
-
16
- raise HumanError::Errors::ResourceNotFoundError.new(
17
- resource_name: Persistable.human_error_resource_name(self),
18
- resource_id: ids)
19
- end
20
- end
21
-
22
- def save!(*args)
23
- super
24
- rescue ActiveRecord::InvalidForeignKey => e
25
- association_info_pattern = /DETAIL: Key \((.*)_id\)=\(([a-f0-9\-]+)\)/
26
- association_name, association_id = e.message.
27
- match(association_info_pattern) \
28
- [1..-1]
29
-
30
- raise HumanError::Errors::AssociationError.new(
31
- resource_name: Persistable.human_error_resource_name(self.class),
32
- association_name: association_name,
33
- association_id: association_id,
34
- attributes: attributes)
35
- rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved
36
- raise HumanError::Errors::ResourcePersistenceError.new(
37
- resource_name: Persistable.human_error_resource_name(self.class),
38
- attributes: attributes,
39
- errors: errors.full_messages)
40
- end
41
-
42
- def self.human_error_resource_name(klass)
43
- last_part_of_class_name = /::(\w+)\z/
44
-
45
- klass.
46
- name[last_part_of_class_name, 1].
47
- underscore.
48
- humanize.
49
- downcase
50
- end
51
-
52
- def self.included(base)
53
- base.extend ClassMethods
54
- end
55
- end
56
- end