active_interaction 1.6.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -5
- data/README.md +35 -32
- data/lib/active_interaction.rb +3 -4
- data/lib/active_interaction/backports.rb +47 -0
- data/lib/active_interaction/base.rb +8 -25
- data/lib/active_interaction/concerns/runnable.rb +4 -14
- data/lib/active_interaction/errors.rb +12 -82
- data/lib/active_interaction/filters/array_filter.rb +3 -9
- data/lib/active_interaction/filters/file_filter.rb +5 -24
- data/lib/active_interaction/filters/hash_filter.rb +6 -13
- data/lib/active_interaction/filters/interface_filter.rb +2 -2
- data/lib/active_interaction/filters/{model_filter.rb → object_filter.rb} +4 -5
- data/lib/active_interaction/locale/en.yml +0 -1
- data/lib/active_interaction/version.rb +1 -1
- data/spec/active_interaction/base_spec.rb +15 -14
- data/spec/active_interaction/concerns/runnable_spec.rb +2 -34
- data/spec/active_interaction/errors_spec.rb +5 -87
- data/spec/active_interaction/filters/array_filter_spec.rb +2 -2
- data/spec/active_interaction/filters/file_filter_spec.rb +4 -4
- data/spec/active_interaction/filters/hash_filter_spec.rb +1 -17
- data/spec/active_interaction/filters/{model_filter_spec.rb → object_filter_spec.rb} +17 -17
- data/spec/active_interaction/integration/array_interaction_spec.rb +10 -0
- data/spec/active_interaction/integration/hash_interaction_spec.rb +12 -2
- data/spec/active_interaction/integration/object_interaction_spec.rb +16 -0
- metadata +8 -11
- data/lib/active_interaction/concerns/transactable.rb +0 -81
- data/spec/active_interaction/concerns/transactable_spec.rb +0 -135
- data/spec/active_interaction/integration/model_interaction_spec.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec03f8a492e5db88366e50b9a918ff40a4e008b3
|
4
|
+
data.tar.gz: 356b91990bfac14981a6d36dffcaafb4e3dd2d33
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a68094094d6dbf8a395a3f709ffd993944512c6edc921ce36f99b4383792de041954cc2d73271a0748102782f89c4e457bb63288ee56eb34e42ff6cb38fbcbd5
|
7
|
+
data.tar.gz: d682f33e94ea7bd25f4f9cf89e2fe3924bc501e608c6d32f469da42d92782f88aca01b43605c69adb5de62e36b2cafe3857307ff927a2306dbbb25ef334c4f93
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,20 @@
|
|
1
|
-
# [
|
1
|
+
# [2.0.0][] (2015-05-06)
|
2
2
|
|
3
|
-
##
|
3
|
+
## Changed
|
4
|
+
|
5
|
+
- [#250][]: Replaced symbolic errors with Rails 5-style detailed errors.
|
6
|
+
- [#269][]: Prevented proc defaults from being eagerly evaluated.
|
7
|
+
- [#264][]: Renamed `model` filter to `object`.
|
8
|
+
- [#213][]: Remove transaction support. Database transactions will need to be
|
9
|
+
handled manually now.
|
10
|
+
- [#214][]: Results are returned from invalid outcomes.
|
11
|
+
- [#164][]: Changed the `hash` filter to use hashes with indifferent access.
|
12
|
+
- [#236][]: Changed the `file` filter to accept anything that responds to `eof?`.
|
13
|
+
|
14
|
+
## Security
|
4
15
|
|
5
|
-
- [#
|
16
|
+
- [#215][]: Rather than symbolizing keys all hashes now use indifferent access.
|
17
|
+
This takes care of potential but unlikely DoS attacks noted in [#163][].
|
6
18
|
|
7
19
|
# [1.6.0][] (2015-05-06)
|
8
20
|
|
@@ -402,7 +414,7 @@
|
|
402
414
|
|
403
415
|
- Initial release.
|
404
416
|
|
405
|
-
[
|
417
|
+
[2.0.0]: https://github.com/orgsync/active_interaction/compare/v1.6.0...v2.0.0
|
406
418
|
[1.6.0]: https://github.com/orgsync/active_interaction/compare/v1.5.1...v1.6.0
|
407
419
|
[1.5.1]: https://github.com/orgsync/active_interaction/compare/v1.5.0...v1.5.1
|
408
420
|
[1.5.0]: https://github.com/orgsync/active_interaction/compare/v1.4.1...v1.5.0
|
@@ -505,6 +517,7 @@
|
|
505
517
|
[#155]: https://github.com/orgsync/active_interaction/issues/155
|
506
518
|
[#156]: https://github.com/orgsync/active_interaction/issues/156
|
507
519
|
[#163]: https://github.com/orgsync/active_interaction/issues/163
|
520
|
+
[#164]: https://github.com/orgsync/active_interaction/issues/164
|
508
521
|
[#165]: https://github.com/orgsync/active_interaction/issues/165
|
509
522
|
[#173]: https://github.com/orgsync/active_interaction/issues/173
|
510
523
|
[#174]: https://github.com/orgsync/active_interaction/issues/174
|
@@ -517,11 +530,17 @@
|
|
517
530
|
[#203]: https://github.com/orgsync/active_interaction/issues/203
|
518
531
|
[#206]: https://github.com/orgsync/active_interaction/issues/206
|
519
532
|
[#207]: https://github.com/orgsync/active_interaction/issues/207
|
533
|
+
[#213]: https://github.com/orgsync/active_interaction/issues/213
|
534
|
+
[#214]: https://github.com/orgsync/active_interaction/issues/214
|
535
|
+
[#215]: https://github.com/orgsync/active_interaction/issues/215
|
520
536
|
[#224]: https://github.com/orgsync/active_interaction/issues/224
|
521
537
|
[#235]: https://github.com/orgsync/active_interaction/issues/235
|
538
|
+
[#236]: https://github.com/orgsync/active_interaction/issues/236
|
522
539
|
[#239]: https://github.com/orgsync/active_interaction/issues/239
|
523
540
|
[#244]: https://github.com/orgsync/active_interaction/issues/244
|
524
541
|
[#248]: https://github.com/orgsync/active_interaction/issues/248
|
542
|
+
[#250]: https://github.com/orgsync/active_interaction/issues/250
|
525
543
|
[#256]: https://github.com/orgsync/active_interaction/issues/256
|
544
|
+
[#264]: https://github.com/orgsync/active_interaction/issues/264
|
526
545
|
[#265]: https://github.com/orgsync/active_interaction/issues/265
|
527
|
-
[#
|
546
|
+
[#269]: https://github.com/orgsync/active_interaction/issues/269
|
data/README.md
CHANGED
@@ -39,7 +39,7 @@ Read more on [the project page][] or check out [the full documentation][].
|
|
39
39
|
- [File](#file)
|
40
40
|
- [Hash](#hash)
|
41
41
|
- [Interface](#interface)
|
42
|
-
- [
|
42
|
+
- [Object](#object)
|
43
43
|
- [String](#string)
|
44
44
|
- [Symbol](#symbol)
|
45
45
|
- [Dates and times](#dates-and-times)
|
@@ -75,13 +75,13 @@ Read more on [the project page][] or check out [the full documentation][].
|
|
75
75
|
Add it to your Gemfile:
|
76
76
|
|
77
77
|
``` rb
|
78
|
-
gem 'active_interaction', '~>
|
78
|
+
gem 'active_interaction', '~> 2.0'
|
79
79
|
```
|
80
80
|
|
81
81
|
Or install it manually:
|
82
82
|
|
83
83
|
``` sh
|
84
|
-
$ gem install active_interaction --version '~>
|
84
|
+
$ gem install active_interaction --version '~> 2.0'
|
85
85
|
```
|
86
86
|
|
87
87
|
This project uses [Semantic Versioning][]. Check out [the change log][] for a
|
@@ -124,8 +124,8 @@ end
|
|
124
124
|
Call `.run` on your interaction to execute it. You must pass a single hash to
|
125
125
|
`.run`. It will return an instance of your interaction. By convention, we call
|
126
126
|
this an outcome. You can use the `#valid?` method to ask the outcome if it's
|
127
|
-
valid. If it's invalid, take a look at its errors with `#errors`.
|
128
|
-
|
127
|
+
valid. If it's invalid, take a look at its errors with `#errors`. In either
|
128
|
+
case, the value returned from `#execute` will be stored in `#result`.
|
129
129
|
|
130
130
|
``` rb
|
131
131
|
outcome = Square.run(x: 'two point one')
|
@@ -379,11 +379,11 @@ InterfaceInteraction.run!(serializer: JSON)
|
|
379
379
|
# => "{\"is_json\":true}"
|
380
380
|
```
|
381
381
|
|
382
|
-
###
|
382
|
+
### Object
|
383
383
|
|
384
|
-
|
385
|
-
either `#is_a?` on the instance or `.===` on the class. Because of that,
|
386
|
-
also works with classes that have mixed modules in with `include`.
|
384
|
+
Object filters allow you to require an instance of a particular class. It
|
385
|
+
checks either `#is_a?` on the instance or `.===` on the class. Because of that,
|
386
|
+
it also works with classes that have mixed modules in with `include`.
|
387
387
|
|
388
388
|
``` rb
|
389
389
|
class Cow
|
@@ -392,17 +392,17 @@ class Cow
|
|
392
392
|
end
|
393
393
|
end
|
394
394
|
|
395
|
-
class
|
396
|
-
|
395
|
+
class ObjectInteraction < ActiveInteraction::Base
|
396
|
+
object :cow
|
397
397
|
|
398
398
|
def execute
|
399
399
|
cow.moo
|
400
400
|
end
|
401
401
|
end
|
402
402
|
|
403
|
-
|
404
|
-
# ActiveInteraction::InvalidInteractionError: Cow is not a valid
|
405
|
-
|
403
|
+
ObjectInteraction.run!(cow: Object.new)
|
404
|
+
# ActiveInteraction::InvalidInteractionError: Cow is not a valid object
|
405
|
+
ObjectInteraction.run!(cow: Cow.new)
|
406
406
|
# => "Moo!"
|
407
407
|
```
|
408
408
|
|
@@ -411,11 +411,11 @@ name is different than your class name, use the `class` option. It can be
|
|
411
411
|
either the class, a string, or a symbol.
|
412
412
|
|
413
413
|
``` rb
|
414
|
-
|
414
|
+
object :dolly1,
|
415
415
|
class: Sheep
|
416
|
-
|
416
|
+
object :dolly2,
|
417
417
|
class: 'Sheep'
|
418
|
-
|
418
|
+
object :dolly3,
|
419
419
|
class: :Sheep
|
420
420
|
```
|
421
421
|
|
@@ -788,7 +788,7 @@ spot.
|
|
788
788
|
|
789
789
|
``` rb
|
790
790
|
class DestroyAccount < ActiveInteraction::Base
|
791
|
-
|
791
|
+
object :account
|
792
792
|
|
793
793
|
def execute
|
794
794
|
account.destroy
|
@@ -822,7 +822,7 @@ Skip to [the predicates section](#predicates) for more information about them.
|
|
822
822
|
|
823
823
|
``` rb
|
824
824
|
class UpdateAccount < ActiveInteraction::Base
|
825
|
-
|
825
|
+
object :account
|
826
826
|
|
827
827
|
string :first_name, :last_name,
|
828
828
|
default: nil
|
@@ -1004,14 +1004,14 @@ end
|
|
1004
1004
|
|
1005
1005
|
### Errors
|
1006
1006
|
|
1007
|
-
ActiveInteraction provides
|
1008
|
-
of errors.
|
1007
|
+
ActiveInteraction provides detailed errors for easier introspection and testing
|
1008
|
+
of errors. Detailed errors improve on regular errors by adding a symbol that
|
1009
1009
|
represents the type of error that has occurred. Let's look at an example where
|
1010
1010
|
an item is purchased using a credit card.
|
1011
1011
|
|
1012
1012
|
``` rb
|
1013
1013
|
class BuyItem < ActiveInteraction::Base
|
1014
|
-
|
1014
|
+
object :credit_card, :item
|
1015
1015
|
hash :options do
|
1016
1016
|
boolean :gift_wrapped
|
1017
1017
|
end
|
@@ -1034,28 +1034,30 @@ errors.
|
|
1034
1034
|
``` rb
|
1035
1035
|
outcome = BuyItem.run(item: 'Thing', options: { gift_wrapped: 'yes' })
|
1036
1036
|
outcome.errors.messages
|
1037
|
-
# => {:credit_card=>["is required"], :item=>["is not a valid
|
1037
|
+
# => {:credit_card=>["is required"], :item=>["is not a valid object"], :options=>["has an invalid nested value (\"gift_wrapped\" => \"yes\")"]}
|
1038
1038
|
```
|
1039
1039
|
|
1040
1040
|
Determining the type of error based on the string is difficult if not
|
1041
|
-
impossible. Calling `#
|
1041
|
+
impossible. Calling `#details` instead of `#messages` on `errors` gives you
|
1042
1042
|
the same list of errors with a testable label representing the error.
|
1043
1043
|
|
1044
1044
|
``` rb
|
1045
|
-
outcome.errors.
|
1046
|
-
# => {
|
1045
|
+
outcome.errors.details
|
1046
|
+
# => {:credit_card=>[{:error=>:missing}], :item=>[{:type=>"object", :error=>:invalid_type}], :options=>[{:name=>"\"gift_wrapped\"", :value=>"\"yes\"", :error=>:invalid_nested}]}
|
1047
1047
|
```
|
1048
1048
|
|
1049
|
-
|
1050
|
-
|
1051
|
-
that the second argument is the error label.
|
1049
|
+
Detailed errors can also be manually added during the execute call by passing a
|
1050
|
+
symbol to `#add` instead of a string.
|
1052
1051
|
|
1053
1052
|
``` rb
|
1054
1053
|
def execute
|
1055
|
-
errors.
|
1054
|
+
errors.add(:monster, :no_passage)
|
1056
1055
|
end
|
1057
1056
|
```
|
1058
1057
|
|
1058
|
+
These types of errors will become standard with Rails 5. ActiveInteraction's
|
1059
|
+
implementation is based off of [active_model-errors_details][].
|
1060
|
+
|
1059
1061
|
ActiveInteraction also supports merging errors. This is useful if you want to
|
1060
1062
|
delegate validation to some other object. For example, if you have an
|
1061
1063
|
interaction that updates a record, you might want that record to validate
|
@@ -1063,7 +1065,7 @@ itself. By using the `#merge!` helper on `errors`, you can do exactly that.
|
|
1063
1065
|
|
1064
1066
|
``` rb
|
1065
1067
|
class UpdateThing < ActiveInteraction::Base
|
1066
|
-
|
1068
|
+
object :thing
|
1067
1069
|
|
1068
1070
|
def execute
|
1069
1071
|
unless thing.save
|
@@ -1180,7 +1182,7 @@ hsilgne:
|
|
1180
1182
|
hash: hsah
|
1181
1183
|
integer: regetni
|
1182
1184
|
interface: ecafretni
|
1183
|
-
|
1185
|
+
object: tcejbo
|
1184
1186
|
string: gnirts
|
1185
1187
|
symbol: lobmys
|
1186
1188
|
time: emit
|
@@ -1225,6 +1227,7 @@ Logo design by [Tyler Lee][].
|
|
1225
1227
|
[the full documentation]: http://rubydoc.info/github/orgsync/active_interaction
|
1226
1228
|
[semantic versioning]: http://semver.org/spec/v2.0.0.html
|
1227
1229
|
[the change log]: CHANGELOG.md
|
1230
|
+
[active_model-errors_details]: https://github.com/cowbell/active_model-errors_details
|
1228
1231
|
[aaron lasseigne]: https://github.com/AaronLasseigne
|
1229
1232
|
[taylor fausak]: https://github.com/tfausak
|
1230
1233
|
[orgsync]: https://github.com/orgsync
|
data/lib/active_interaction.rb
CHANGED
@@ -9,7 +9,7 @@ require 'active_model'
|
|
9
9
|
#
|
10
10
|
# @since 1.0.0
|
11
11
|
#
|
12
|
-
# @version
|
12
|
+
# @version 2.0.0
|
13
13
|
module ActiveInteraction
|
14
14
|
DEPRECATOR =
|
15
15
|
if ::ActiveSupport::Deprecation.respond_to?(:new)
|
@@ -31,7 +31,6 @@ require 'active_interaction/concerns/active_modelable'
|
|
31
31
|
require 'active_interaction/concerns/active_recordable'
|
32
32
|
require 'active_interaction/concerns/hashable'
|
33
33
|
require 'active_interaction/concerns/missable'
|
34
|
-
require 'active_interaction/concerns/transactable'
|
35
34
|
require 'active_interaction/concerns/runnable'
|
36
35
|
|
37
36
|
require 'active_interaction/grouped_input'
|
@@ -42,6 +41,7 @@ require 'active_interaction/modules/validation'
|
|
42
41
|
require 'active_interaction/filter_column'
|
43
42
|
require 'active_interaction/filter'
|
44
43
|
require 'active_interaction/filters/abstract_filter'
|
44
|
+
require 'active_interaction/filters/interface_filter'
|
45
45
|
require 'active_interaction/filters/abstract_date_time_filter'
|
46
46
|
require 'active_interaction/filters/abstract_numeric_filter'
|
47
47
|
require 'active_interaction/filters/array_filter'
|
@@ -53,8 +53,7 @@ require 'active_interaction/filters/file_filter'
|
|
53
53
|
require 'active_interaction/filters/float_filter'
|
54
54
|
require 'active_interaction/filters/hash_filter'
|
55
55
|
require 'active_interaction/filters/integer_filter'
|
56
|
-
require 'active_interaction/filters/
|
57
|
-
require 'active_interaction/filters/model_filter'
|
56
|
+
require 'active_interaction/filters/object_filter'
|
58
57
|
require 'active_interaction/filters/string_filter'
|
59
58
|
require 'active_interaction/filters/symbol_filter'
|
60
59
|
require 'active_interaction/filters/time_filter'
|
@@ -16,6 +16,53 @@ module ActiveInteraction
|
|
16
16
|
class Errors # rubocop:disable Style/Documentation
|
17
17
|
# Required for Rails < 3.2.13.
|
18
18
|
protected :initialize_dup
|
19
|
+
|
20
|
+
# Required for Rails < 5.
|
21
|
+
#
|
22
|
+
# Extracted from active_model-errors_details 1.2.0. Modified to add support
|
23
|
+
# for ActiveModel 3.2.0.
|
24
|
+
module Details
|
25
|
+
extend ActiveSupport::Concern
|
26
|
+
|
27
|
+
CALLBACKS_OPTIONS = ::ActiveModel::Errors::CALLBACKS_OPTIONS
|
28
|
+
private_constant :CALLBACKS_OPTIONS
|
29
|
+
|
30
|
+
included do
|
31
|
+
attr_reader :details
|
32
|
+
|
33
|
+
%w[initialize initialize_dup add clear delete].each do |method|
|
34
|
+
alias_method_chain method, :details
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize_with_details(base)
|
39
|
+
@details = Hash.new { |details, attribute| details[attribute] = [] }
|
40
|
+
initialize_without_details(base)
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize_dup_with_details(other)
|
44
|
+
@details = other.details.deep_dup
|
45
|
+
initialize_dup_without_details(other)
|
46
|
+
end
|
47
|
+
|
48
|
+
def add_with_details(attribute, message = :invalid, options = {})
|
49
|
+
message = message.call if message.respond_to?(:call)
|
50
|
+
error = options.except(*CALLBACKS_OPTIONS).merge(error: message)
|
51
|
+
details[attribute].push(error)
|
52
|
+
add_without_details(attribute, message, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
def clear_with_details
|
56
|
+
details.clear
|
57
|
+
clear_without_details
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete_with_details(attribute)
|
61
|
+
details.delete(attribute)
|
62
|
+
delete_without_details(attribute)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
include Details unless method_defined?(:details)
|
19
66
|
end
|
20
67
|
|
21
68
|
class HashFilter # rubocop:disable Style/Documentation
|
@@ -59,28 +59,6 @@ module ActiveInteraction
|
|
59
59
|
#
|
60
60
|
# @raise (see ActiveInteraction::Runnable::ClassMethods#run!)
|
61
61
|
|
62
|
-
# @!method transaction(enable, options = {})
|
63
|
-
# Configure transactions by enabling or disabling them and setting
|
64
|
-
# their options.
|
65
|
-
#
|
66
|
-
# @example Disable transactions
|
67
|
-
# Class.new(ActiveInteraction::Base) do
|
68
|
-
# transaction false
|
69
|
-
# end
|
70
|
-
#
|
71
|
-
# @example Use different transaction options
|
72
|
-
# Class.new(ActiveInteraction::Base) do
|
73
|
-
# transaction true, isolation: :serializable
|
74
|
-
# end
|
75
|
-
#
|
76
|
-
# @param enable [Boolean] Should transactions be enabled?
|
77
|
-
# @param options [Hash] Options to pass to
|
78
|
-
# `ActiveRecord::Base.transaction`.
|
79
|
-
#
|
80
|
-
# @return [nil]
|
81
|
-
#
|
82
|
-
# @since 1.2.0
|
83
|
-
|
84
62
|
# Get or set the description.
|
85
63
|
#
|
86
64
|
# @example
|
@@ -174,7 +152,13 @@ module ActiveInteraction
|
|
174
152
|
attr_accessor filter.name
|
175
153
|
define_method("#{filter.name}?") { !public_send(filter.name).nil? }
|
176
154
|
|
177
|
-
filter
|
155
|
+
eagerly_evaluate_default(filter)
|
156
|
+
end
|
157
|
+
|
158
|
+
# @param filter [Filter]
|
159
|
+
def eagerly_evaluate_default(filter)
|
160
|
+
default = filter.options[:default]
|
161
|
+
filter.default if default && !default.is_a?(Proc)
|
178
162
|
end
|
179
163
|
end
|
180
164
|
|
@@ -201,8 +185,7 @@ module ActiveInteraction
|
|
201
185
|
#
|
202
186
|
# Runs the business logic associated with the interaction. This method is
|
203
187
|
# only run when there are no validation errors. The return value is
|
204
|
-
# placed into {#result}.
|
205
|
-
# if ActiveRecord is available (see {.transaction}).
|
188
|
+
# placed into {#result}.
|
206
189
|
#
|
207
190
|
# @raise (see ActiveInteraction::Runnable#execute)
|
208
191
|
|
@@ -6,14 +6,12 @@ module ActiveInteraction
|
|
6
6
|
#
|
7
7
|
# @note Must be included after `ActiveModel::Validations`.
|
8
8
|
#
|
9
|
-
# Runs code
|
10
|
-
# validation errors.
|
9
|
+
# Runs code and provides the result.
|
11
10
|
#
|
12
11
|
# @private
|
13
12
|
module Runnable
|
14
13
|
extend ActiveSupport::Concern
|
15
14
|
include ActiveModel::Validations
|
16
|
-
include ActiveInteraction::Transactable
|
17
15
|
|
18
16
|
included do
|
19
17
|
define_callbacks :execute
|
@@ -41,13 +39,8 @@ module ActiveInteraction
|
|
41
39
|
#
|
42
40
|
# @return (see #result)
|
43
41
|
def result=(result)
|
44
|
-
|
45
|
-
|
46
|
-
@_interaction_valid = true
|
47
|
-
else
|
48
|
-
@_interaction_result = nil
|
49
|
-
@_interaction_valid = false
|
50
|
-
end
|
42
|
+
@_interaction_result = result
|
43
|
+
@_interaction_valid = errors.empty?
|
51
44
|
end
|
52
45
|
|
53
46
|
# @return [Boolean]
|
@@ -82,15 +75,12 @@ module ActiveInteraction
|
|
82
75
|
def run
|
83
76
|
return unless valid?
|
84
77
|
|
85
|
-
self.result =
|
78
|
+
self.result =
|
86
79
|
begin
|
87
80
|
run_callbacks(:execute) { execute }
|
88
81
|
rescue Interrupt => interrupt
|
89
82
|
merge_errors_onto_base(interrupt.outcome.errors)
|
90
|
-
|
91
|
-
raise ActiveRecord::Rollback if self.class.transaction?
|
92
83
|
end
|
93
|
-
end
|
94
84
|
end
|
95
85
|
|
96
86
|
def merge_errors_onto_base(new_errors)
|