action_logic 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +70 -54
- data/lib/action_logic/action_validation.rb +7 -3
- data/lib/action_logic/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec1c25ca6b1d98aead3c8da72aaa11ae58c1b9fe
|
4
|
+
data.tar.gz: c27b50ad7c730bcf5b370b3016b8dc8fabca1cc9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8340bda2fb890fdea4c2cf4177763c347dfdcbc247ab4a49b1def06851cd99cfc633c3c9c671272a16ce7dd960fee432d9e4abc5af341a499d33a83202c5b61f
|
7
|
+
data.tar.gz: c9f53e0e7f74cb63618e1b064a940027166ba8f9165c9dbdf0ac4cd289a25e19ce90d0fbfaa34433a13d82a65c654c6cc8144ddd8d27b78158a4c58253b900b9
|
data/README.md
CHANGED
@@ -162,9 +162,9 @@ To implement an `ActionTask` class you must define a `call` method. You can also
|
|
162
162
|
class ActionTaskExample
|
163
163
|
include ActionLogic::ActionTask
|
164
164
|
|
165
|
-
validates_before :expected_attribute1 => { :type =>
|
166
|
-
:expected_attribute2 => { :type =>
|
167
|
-
validates_after :example_attribute1 => { :type =>
|
165
|
+
validates_before :expected_attribute1 => { :type => String },
|
166
|
+
:expected_attribute2 => { :type => Fixnum, :presence => true }
|
167
|
+
validates_after :example_attribute1 => { :type => String, :presence => ->(example_attribute1) { !example_attribute1.empty? } }
|
168
168
|
|
169
169
|
def call
|
170
170
|
# adds `example_attribute1` to the shared `context` with the value "Example value"
|
@@ -179,30 +179,37 @@ result = ActionTaskExample.execute(:expected_attribute1 => "example", :expected_
|
|
179
179
|
result # => #<ActionLogic::ActionContext expected_attribute1="example", expected_attribute2=123, status=:success, example_attribute1="New value from context attributes: example 123">
|
180
180
|
```
|
181
181
|
|
182
|
-
The `ActionTaskExample` is invoked using the static method `execute` which takes an optional hash of attributes that is converted into an `ActionContext`.
|
182
|
+
The `ActionTaskExample` is invoked using the static method `execute` which takes an optional hash of attributes that is converted into an `ActionContext`.
|
183
|
+
Assuming the before validations are satisfied, the `call` method is invoked. In the body of the `call` method the `ActionTask` can access the shared `ActionContext`
|
184
|
+
instance via a `context` object. This shared `context` object allows for getting and setting attributes as needed. When the `call` method returns, the `context`
|
185
|
+
is validated against any defined after validations, and the `context` is then returned to the caller.
|
183
186
|
|
184
187
|
The diagram below is a visual representation of how an `ActionTask` is evaluted when its `execute` method is invoked from a caller:
|
185
188
|
|
186
189
|
<img src="https://raw.githubusercontent.com/rewinfrey/action_logic/master/resources/action_task_diagram.png" />
|
187
190
|
|
188
|
-
Although this example is for the `ActionTask` abstraction, `ActionUseCase` and `ActionCoordinator` follow the same pattern. The difference is that `ActionUseCase`
|
191
|
+
Although this example is for the `ActionTask` abstraction, `ActionUseCase` and `ActionCoordinator` follow the same pattern. The difference is that `ActionUseCase`
|
192
|
+
is designed to organize multiple `ActionTasks`, and `ActionCoordinator` is designed to organize many `ActionUseCases`.
|
189
193
|
|
190
194
|
### ActionUseCase
|
191
195
|
|
192
|
-
As business logic grows in complexity the number of steps or tasks required to fulfill that business logic tends to increase. Managing this complexity is a problem every team must face.
|
196
|
+
As business logic grows in complexity the number of steps or tasks required to fulfill that business logic tends to increase. Managing this complexity is a problem every team must face.
|
197
|
+
Abstractions can help teams of varying experience levels work together and promote code that remains modular and simple to understand and extend. `ActionUseCase` represents a layer of
|
198
|
+
abstraction that organizes multiple `ActionTasks` and executes each `ActionTask` in the order they are defined. Each task receives the same shared `context` so tasks can be composed together.
|
193
199
|
|
194
|
-
To implement an `ActionUseCase` class you must define a `call` method and a `tasks` method. You also can specify any before, after or around validations or an error handler.
|
200
|
+
To implement an `ActionUseCase` class you must define a `call` method and a `tasks` method. You also can specify any before, after or around validations or an error handler.
|
201
|
+
The following is an example showcasing how an `ActionUseCase` class organizes the execution of multiple `ActionTasks` and defines before and after validations on the shared `context`:
|
195
202
|
|
196
203
|
```ruby
|
197
204
|
class ActionUseCaseExample
|
198
205
|
include ActionLogic::ActionUseCase
|
199
206
|
|
200
|
-
validates_before :expected_attribute1 => { :type =>
|
201
|
-
:expected_attribute2 => { :type =>
|
202
|
-
validates_after :example_task1 => { :type =>
|
203
|
-
:example_task2 => { :type =>
|
204
|
-
:example_task3 => { :type =>
|
205
|
-
:example_usecase1 => { :type =>
|
207
|
+
validates_before :expected_attribute1 => { :type => String },
|
208
|
+
:expected_attribute2 => { :type => Fixnum, :presence => true }
|
209
|
+
validates_after :example_task1 => { :type => TrueClass, :presence => true },
|
210
|
+
:example_task2 => { :type => TrueClass, :presence => true },
|
211
|
+
:example_task3 => { :type => TrueClass, :presence => true },
|
212
|
+
:example_usecase1 => { :type => TrueClass, :presence => true }
|
206
213
|
|
207
214
|
# The `call` method is invoked prior to invoking any of the ActionTasks defined by the `tasks` method.
|
208
215
|
# The purpose of the `call` method allows us to prepare the shared `context` prior to invoking the ActionTasks.
|
@@ -220,7 +227,7 @@ end
|
|
220
227
|
|
221
228
|
class ActionTaskExample1
|
222
229
|
include ActionLogic::ActionTask
|
223
|
-
validates_after :example_task1 => { :type =>
|
230
|
+
validates_after :example_task1 => { :type => TrueClass, :presence => true }
|
224
231
|
|
225
232
|
def call
|
226
233
|
context # => #<ActionLogic::ActionContext expected_attribute1="example", expected_attribute2=123, status=:success, example_usecase1=true>
|
@@ -230,7 +237,7 @@ end
|
|
230
237
|
|
231
238
|
class ActionTaskExample2
|
232
239
|
include ActionLogic::ActionTask
|
233
|
-
validates_after :example_task2 => { :type =>
|
240
|
+
validates_after :example_task2 => { :type => TrueClass, :presence => true }
|
234
241
|
|
235
242
|
def call
|
236
243
|
context # => #<ActionLogic::ActionContext expected_attribute1="example", expected_attribute2=123, status=:success, example_usecase1=true, example_task1=true>
|
@@ -240,7 +247,7 @@ end
|
|
240
247
|
|
241
248
|
class ActionTaskExample3
|
242
249
|
include ActionLogic::ActionTask
|
243
|
-
validates_after :example_task3 => { :type =>
|
250
|
+
validates_after :example_task3 => { :type => TrueClass, :presence => true }
|
244
251
|
|
245
252
|
def call
|
246
253
|
context # => #<ActionLogic::ActionContext expected_attribute1="example", expected_attribute2=123, status=:success, example_usecase1=true, example_task1=true, example_task2=true>
|
@@ -254,17 +261,24 @@ result = ActionUseCaseExample.execute(:expected_attribute1 => "example", :expect
|
|
254
261
|
result # => #<ActionLogic::ActionContext expected_attribute1="example", expected_attribute2=123, status=:success, example_usecase1=true, example_task1=true, example_task2=true, example_task3=true>
|
255
262
|
```
|
256
263
|
|
257
|
-
By following the value of the shared `context` from the `ActionUseCaseExample` to each of the `ActionTask` classes, it is possible to see how the shared `context`
|
264
|
+
By following the value of the shared `context` from the `ActionUseCaseExample` to each of the `ActionTask` classes, it is possible to see how the shared `context`
|
265
|
+
is mutated to accomodate the various attributes and their values each execution context adds to the `context`. It also reveals the order in which the `ActionTasks`
|
266
|
+
are evaluated, and indicates that the `call` method of the `ActionUseCaseExample` is invoked prior to any of the `ActionTasks` defined in the `tasks` method.
|
258
267
|
|
259
|
-
To help visualize the flow of execution when an `ActionUseCase` is invoked, this diagram aims to illustrate the relationship between `ActionUseCase` and `ActionTasks`
|
268
|
+
To help visualize the flow of execution when an `ActionUseCase` is invoked, this diagram aims to illustrate the relationship between `ActionUseCase` and `ActionTasks`
|
269
|
+
and the order in which operations are performed:
|
260
270
|
|
261
271
|
<img src="https://raw.githubusercontent.com/rewinfrey/action_logic/master/resources/action_use_case_diagram.png" />
|
262
272
|
|
263
273
|
### ActionCoordinator
|
264
274
|
|
265
|
-
Sometimes the behavior we wish our Ruby or Rails application to provide requires us to coordinate work between various domains of our application's business logic.
|
275
|
+
Sometimes the behavior we wish our Ruby or Rails application to provide requires us to coordinate work between various domains of our application's business logic.
|
276
|
+
The `ActionCoordinator` abstraction is intended to help coordinate multiple `ActionUseCases` by allowing you to define a plan of which `ActionUseCases` to invoke
|
277
|
+
depending on the outcome of each `ActionUseCase` execution. The `ActionCoordinator` abstraction is the highest level of abstraction in `ActionLogic`.
|
266
278
|
|
267
|
-
To implement an `ActionCoordinator` class, you must define a `call` method in addition to a `plan` method. The purpose of the `plan` method is to define a state
|
279
|
+
To implement an `ActionCoordinator` class, you must define a `call` method in addition to a `plan` method. The purpose of the `plan` method is to define a state
|
280
|
+
transition map that links together the various `ActionUseCase` classes the `ActionCoordinator` is organizing, as well as allowing you to define error or halt
|
281
|
+
scenarios based on the result of each `ActionUseCase`. The following code example demonstrates a simple `ActionCoordinator`:
|
268
282
|
|
269
283
|
```ruby
|
270
284
|
class ActionCoordinatorExample
|
@@ -289,7 +303,7 @@ end
|
|
289
303
|
class ActionUseCaseExample1
|
290
304
|
include ActionLogic::ActionUseCase
|
291
305
|
|
292
|
-
validates_before :required_attribute1 => { :type =>
|
306
|
+
validates_before :required_attribute1 => { :type => String }
|
293
307
|
|
294
308
|
def call
|
295
309
|
context # => #<ActionLogic::ActionContext status=:success, required_attribute1="required attribute 1", required_attribute2="required attribute 2">
|
@@ -305,7 +319,7 @@ end
|
|
305
319
|
class ActionUseCaseExample2
|
306
320
|
include ActionLogic::ActionUseCase
|
307
321
|
|
308
|
-
validates_before :required_attribute2 => { :type =>
|
322
|
+
validates_before :required_attribute2 => { :type => String }
|
309
323
|
|
310
324
|
def call
|
311
325
|
context # => #<ActionLogic::ActionContext status=:success, required_attribute1="required attribute 1", required_attribute2="required attribute 2", example_usecase1=true, example_task1=true>
|
@@ -334,7 +348,7 @@ end
|
|
334
348
|
|
335
349
|
class ActionTaskExample1
|
336
350
|
include ActionLogic::ActionTask
|
337
|
-
validates_after :example_task1 => { :type =>
|
351
|
+
validates_after :example_task1 => { :type => TrueClass, :presence => true }
|
338
352
|
|
339
353
|
def call
|
340
354
|
context # => #<ActionLogic::ActionContext status=:success, required_attribute1="required attribute 1", required_attribute2="required attribute 2", example_usecase1=true>
|
@@ -344,7 +358,7 @@ end
|
|
344
358
|
|
345
359
|
class ActionTaskExample2
|
346
360
|
include ActionLogic::ActionTask
|
347
|
-
validates_after :example_task2 => { :type =>
|
361
|
+
validates_after :example_task2 => { :type => TrueClass, :presence => true }
|
348
362
|
|
349
363
|
def call
|
350
364
|
context # => #<ActionLogic::ActionContext status=:success, required_attribute1="required attribute 1", required_attribute2="required attribute 2", example_usecase1=true, example_task1=true, example_usecase2=true>
|
@@ -360,9 +374,9 @@ result # => #<ActionLogic::ActionContext status=:success, required_attribute1="r
|
|
360
374
|
<img src="https://raw.githubusercontent.com/rewinfrey/action_logic/master/resources/action_coordinator_diagram.png" />
|
361
375
|
|
362
376
|
### Succeeding an `ActionContext`
|
363
|
-
By default, the value of the `status` attribute of instances of `ActionContext` is `:success`. Normally this is useful information for the caller of an `ActionTask`,
|
364
|
-
because it informs the caller that the various execution context(s) were successful. In other words, a `:success` status
|
365
|
-
or halted execution.
|
377
|
+
By default, the value of the `status` attribute of instances of `ActionContext` is `:success`. Normally this is useful information for the caller of an `ActionTask`,
|
378
|
+
`ActionUseCase` or `ActionCoordinator` because it informs the caller that the various execution context(s) were successful. In other words, a `:success` status
|
379
|
+
indicates that none of the execution contexts had a failure or halted execution.
|
366
380
|
|
367
381
|
### Failing an `ActionContext`
|
368
382
|
Using `context.fail!` does two important things: it immediately stops the execution of any proceeding business logic (prevents any additional `ActionTasks` from executing)
|
@@ -589,20 +603,22 @@ of `ActionContext`. To understand the default types `ActionLogic` validates agai
|
|
589
603
|
class ActionTaskExample
|
590
604
|
include ActionLogic::ActionTask
|
591
605
|
|
592
|
-
validates_after :integer_test => { :type =>
|
593
|
-
:float_test => { :type =>
|
594
|
-
:string_test => { :type =>
|
595
|
-
:
|
596
|
-
:
|
597
|
-
:
|
598
|
-
:
|
599
|
-
:
|
606
|
+
validates_after :integer_test => { :type => Fixnum },
|
607
|
+
:float_test => { :type => Float },
|
608
|
+
:string_test => { :type => String },
|
609
|
+
:truthy_test => { :type => TrueClass },
|
610
|
+
:falsey_test => { :type => FalseClass },
|
611
|
+
:hash_test => { :type => Hash },
|
612
|
+
:array_test => { :type => Array },
|
613
|
+
:symbol_test => { :type => Symbol },
|
614
|
+
:nil_test => { :type => NilClass }
|
600
615
|
|
601
616
|
def call
|
602
617
|
context.integer_test = 123
|
603
618
|
context.float_test = 1.0
|
604
619
|
context.string_test = "test"
|
605
|
-
context.
|
620
|
+
context.truthy_test = true
|
621
|
+
context.falsey_test = false
|
606
622
|
context.hash_test = {}
|
607
623
|
context.array_test = []
|
608
624
|
context.symbol_test = :symbol
|
@@ -616,7 +632,8 @@ result # => #<ActionLogic::ActionContext status=:success,
|
|
616
632
|
# integer_test=123,
|
617
633
|
# float_test=1.0,
|
618
634
|
# string_test="test",
|
619
|
-
#
|
635
|
+
# truthy_test=true,
|
636
|
+
# falsey_test=false,
|
620
637
|
# hash_test={},
|
621
638
|
# array_test=[],
|
622
639
|
# symbol_test=:symbol,
|
@@ -624,7 +641,7 @@ result # => #<ActionLogic::ActionContext status=:success,
|
|
624
641
|
```
|
625
642
|
|
626
643
|
It's important to point out that Ruby's `true` and `false` are not `Boolean` but `TrueClass` and `FalseClass` respectively. Additionally, `nil`'s type is `NilClass` in Ruby.
|
627
|
-
|
644
|
+
Also potentially surprising to some is that Ruby's integer type is of class `Fixnum`, but floats are of class `Float`.
|
628
645
|
|
629
646
|
As we saw with attribute validations, if an attribute's value does not conform to the type expected, `ActionLogic` will raise an `ActionLogic::AttributeTypeError`
|
630
647
|
with a detailed description about which attribute's value failed the validation:
|
@@ -633,14 +650,14 @@ with a detailed description about which attribute's value failed the validation:
|
|
633
650
|
class ActionTaskExample
|
634
651
|
include ActionLogic::ActionTask
|
635
652
|
|
636
|
-
validates_after :integer_test => { :type =>
|
653
|
+
validates_after :integer_test => { :type => Fixnum }
|
637
654
|
|
638
655
|
def call
|
639
656
|
context.integer_test = 1.0
|
640
657
|
end
|
641
658
|
end
|
642
659
|
|
643
|
-
ActionTaskExample.execute # ~> ["Attribute: integer_test with value: 1.0 was expected to be of type
|
660
|
+
ActionTaskExample.execute # ~> ["Attribute: integer_test with value: 1.0 was expected to be of type Fixnum but is Float"] (ActionLogic::AttributeTypeError)
|
644
661
|
```
|
645
662
|
|
646
663
|
In addition to the above default types it is possible to also validate against user defined types.
|
@@ -657,7 +674,7 @@ end
|
|
657
674
|
class ActionTaskExample
|
658
675
|
include ActionLogic::ActionTask
|
659
676
|
|
660
|
-
validates_after :example_attribute => { :type =>
|
677
|
+
validates_after :example_attribute => { :type => ExampleClass }
|
661
678
|
|
662
679
|
def call
|
663
680
|
context.example_attribute = ExampleClass.new
|
@@ -670,8 +687,7 @@ result # => #<ActionLogic::ActionContext status=:success, example_attribute=#<Ex
|
|
670
687
|
```
|
671
688
|
|
672
689
|
In the above example, a custom class `ExampleClass` is defined. In order to type validate against this class, the required format for the name of the class is simply
|
673
|
-
the
|
674
|
-
`ReallyLongClassNameThatBreaks80ColumnsInVimRule` becomes `:reallylongclassnamethatbreaks80columnsinvimrule` and so on.
|
690
|
+
the class constant `ExampleClass`.
|
675
691
|
|
676
692
|
If a custom type validation fails, `ActionLogic` provides the same `ActionLogic::AttributeTypeError` with a detailed explanation about what attribute is in violation
|
677
693
|
of the type validation:
|
@@ -686,14 +702,14 @@ end
|
|
686
702
|
class ActionTaskExample
|
687
703
|
include ActionLogic::ActionTask
|
688
704
|
|
689
|
-
validates_after :example_attribute => { :type =>
|
705
|
+
validates_after :example_attribute => { :type => ExampleClass }
|
690
706
|
|
691
707
|
def call
|
692
708
|
context.example_attribute = OtherClass.new
|
693
709
|
end
|
694
710
|
end
|
695
711
|
|
696
|
-
ActionTaskExample.execute # ~> ["Attribute: example_attribute with value: #<OtherClass:0x007fb5ca04edb8> was expected to be of type
|
712
|
+
ActionTaskExample.execute # ~> ["Attribute: example_attribute with value: #<OtherClass:0x007fb5ca04edb8> was expected to be of type ExampleClass but is OtherClass"] (ActionLogic::AttributeTypeError)
|
697
713
|
```
|
698
714
|
|
699
715
|
Attribute and type validations are very helpful, but in some situations this is not enough. Additionally, `ActionLogic` provides presence validation so you can also verify that
|
@@ -796,7 +812,7 @@ validation on a single attribute:
|
|
796
812
|
class ActionTaskExample
|
797
813
|
include ActionLogic::ActionTask
|
798
814
|
|
799
|
-
validates_before :example_attribute => { :type =>
|
815
|
+
validates_before :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } }
|
800
816
|
|
801
817
|
def call
|
802
818
|
end
|
@@ -813,8 +829,8 @@ The following example illustrates how to specify a before validation for multipl
|
|
813
829
|
class ActionTaskExample
|
814
830
|
include ActionLogic::ActionTask
|
815
831
|
|
816
|
-
validates_before :example_attribute => { :type =>
|
817
|
-
:example_attribute2 => { :type =>
|
832
|
+
validates_before :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } },
|
833
|
+
:example_attribute2 => { :type => Fixnum }
|
818
834
|
|
819
835
|
def call
|
820
836
|
end
|
@@ -838,7 +854,7 @@ validation on a single attribute:
|
|
838
854
|
class ActionTaskExample
|
839
855
|
include ActionLogic::ActionTask
|
840
856
|
|
841
|
-
validates_after :example_attribute => { :type =>
|
857
|
+
validates_after :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } }
|
842
858
|
|
843
859
|
def call
|
844
860
|
context.example_attribute = [1, 2, 3]
|
@@ -855,8 +871,8 @@ The following example illustrates how to specify an after validation for multipl
|
|
855
871
|
class ActionTaskExample
|
856
872
|
include ActionLogic::ActionTask
|
857
873
|
|
858
|
-
validates_after :example_attribute => { :type =>
|
859
|
-
:example_attribute2 => { :type =>
|
874
|
+
validates_after :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } },
|
875
|
+
:example_attribute2 => { :type => Fixnum }
|
860
876
|
|
861
877
|
def call
|
862
878
|
context.example_attribute = [1, 2, 3]
|
@@ -882,7 +898,7 @@ validation on a single attribute:
|
|
882
898
|
class ActionTaskExample
|
883
899
|
include ActionLogic::ActionTask
|
884
900
|
|
885
|
-
validates_around :example_attribute => { :type =>
|
901
|
+
validates_around :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } }
|
886
902
|
|
887
903
|
def call
|
888
904
|
end
|
@@ -898,8 +914,8 @@ The following example illustrates how to specify an around validation for multip
|
|
898
914
|
class ActionTaskExample
|
899
915
|
include ActionLogic::ActionTask
|
900
916
|
|
901
|
-
validates_around :example_attribute => { :type =>
|
902
|
-
:example_attribute2 => { :type =>
|
917
|
+
validates_around :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } },
|
918
|
+
:example_attribute2 => { :type => Fixnum }
|
903
919
|
|
904
920
|
def call
|
905
921
|
end
|
@@ -59,7 +59,7 @@ module ActionLogic
|
|
59
59
|
expected_attributes = validations.keys || []
|
60
60
|
missing_attributes = expected_attributes - existing_attributes
|
61
61
|
|
62
|
-
raise ActionLogic::MissingAttributeError.new(missing_attributes) if missing_attributes.any?
|
62
|
+
raise ActionLogic::MissingAttributeError.new(error_message_format(missing_attributes.join(", ") + " attributes are missing")) if missing_attributes.any?
|
63
63
|
end
|
64
64
|
|
65
65
|
def validate_types!(validations)
|
@@ -74,7 +74,7 @@ module ActionLogic
|
|
74
74
|
collection
|
75
75
|
end
|
76
76
|
|
77
|
-
raise ActionLogic::AttributeTypeError.new(type_errors) if type_errors.any?
|
77
|
+
raise ActionLogic::AttributeTypeError.new(error_message_format(type_errors.join(", "))) if type_errors.any?
|
78
78
|
end
|
79
79
|
|
80
80
|
def validate_presence!(validations)
|
@@ -88,7 +88,7 @@ module ActionLogic
|
|
88
88
|
elsif expected_validation[:presence].class == Proc
|
89
89
|
collection << "Attribute: #{expected_attribute} is missing value in context but custom presence validation was specified" unless expected_validation[:presence].call(context[expected_attribute])
|
90
90
|
else
|
91
|
-
raise ActionLogic::UnrecognizablePresenceValidatorError.new("Presence validator: #{expected_validation[:presence]} is not a supported format")
|
91
|
+
raise ActionLogic::UnrecognizablePresenceValidatorError.new(error_message_format("Presence validator: #{expected_validation[:presence]} is not a supported format"))
|
92
92
|
end
|
93
93
|
|
94
94
|
collection
|
@@ -96,5 +96,9 @@ module ActionLogic
|
|
96
96
|
|
97
97
|
raise ActionLogic::PresenceError.new(presence_errors) if presence_errors.any?
|
98
98
|
end
|
99
|
+
|
100
|
+
def error_message_format(error_string)
|
101
|
+
"context: #{self.class} message: #{error_string}"
|
102
|
+
end
|
99
103
|
end
|
100
104
|
end
|
data/lib/action_logic/version.rb
CHANGED