lev 10.1.0 → 12.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/lev/error_transferer.rb +5 -5
- data/lib/lev/error_translator.rb +4 -5
- data/lib/lev/version.rb +1 -1
- data/lib/lev.rb +1 -2
- data/spec/{better_active_model_errors_spec.rb → active_model_errors_spec.rb} +10 -9
- data/spec/spec_helper.rb +2 -2
- metadata +41 -42
- data/lib/lev/better_active_model_errors.rb +0 -421
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9b8ecaa0018e8014f478eff02949764ffaf1ad73f50c9d64be7fd6889b9758d
|
4
|
+
data.tar.gz: ff47d80e42f5ef65335c4da2636efe6ee0bc13a78a650b1b13833e5e1aa84763
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 858c6dba66a94ba31b6129f3602d55d83e7cc713fe9a7710f3e6109c7e80cb3cc67a568c4257d9d44d32c90c10c17d943700ef36e9eed1e82b114ca9f5fa9f9c
|
7
|
+
data.tar.gz: 74bdcc356356641f04717adbcf74c7c3945522ab0b472ed8eef4cba407f55022cea2541092c4bca0a70deac1cb3d730454a1d98dfcf28a73e631abc6a3c41157
|
data/lib/lev/error_transferer.rb
CHANGED
@@ -5,16 +5,16 @@ module Lev
|
|
5
5
|
def self.transfer(source, target_routine, input_mapper, fail_if_errors=false)
|
6
6
|
case source
|
7
7
|
when ActiveRecord::Base, Lev::Paramifier
|
8
|
-
source.errors.
|
8
|
+
source.errors.each do |error|
|
9
9
|
target_routine.nonfatal_error(
|
10
|
-
code: type,
|
10
|
+
code: error.type,
|
11
11
|
data: {
|
12
12
|
model: source,
|
13
|
-
attribute: attribute
|
13
|
+
attribute: error.attribute
|
14
14
|
},
|
15
15
|
kind: :activerecord,
|
16
|
-
message: message,
|
17
|
-
offending_inputs: input_mapper.map(attribute)
|
16
|
+
message: error.message,
|
17
|
+
offending_inputs: input_mapper.map(error.attribute)
|
18
18
|
)
|
19
19
|
end
|
20
20
|
when Lev::Errors
|
data/lib/lev/error_translator.rb
CHANGED
@@ -5,15 +5,14 @@ module Lev
|
|
5
5
|
def self.translate(error)
|
6
6
|
case error.kind
|
7
7
|
when :activerecord
|
8
|
-
model = error.data[:model]
|
9
8
|
attribute = error.data[:attribute]
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
message = error.message
|
10
|
+
model = error.data[:model]
|
11
|
+
ActiveModel::Error.full_message(attribute, message, model)
|
13
12
|
else
|
14
13
|
message = error.message.to_s
|
15
14
|
message.empty? ? error.code.to_s : message
|
16
|
-
end
|
15
|
+
end
|
17
16
|
end
|
18
17
|
|
19
18
|
end
|
data/lib/lev/version.rb
CHANGED
data/lib/lev.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "action_view"
|
2
2
|
require "active_job"
|
3
3
|
require "transaction_isolation"
|
4
|
-
require "
|
4
|
+
require "open_stax_transaction_retry"
|
5
5
|
require "active_attr"
|
6
6
|
require "hashie"
|
7
7
|
|
@@ -9,7 +9,6 @@ require "lev/version"
|
|
9
9
|
require "lev/object"
|
10
10
|
require "lev/utilities"
|
11
11
|
require "lev/exceptions"
|
12
|
-
require "lev/better_active_model_errors"
|
13
12
|
require "lev/term_mapper"
|
14
13
|
require "lev/outputs"
|
15
14
|
require "lev/routine"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
RSpec.describe '
|
3
|
+
RSpec.describe 'ActiveModelErrors' do
|
4
4
|
class DummyModel
|
5
5
|
def self.human_attribute_name(attr, default='')
|
6
6
|
return attr.capitalize
|
@@ -8,10 +8,11 @@ RSpec.describe 'BetterActiveModelErrors' do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
let(:test_model) { DummyModel.new }
|
11
|
-
let(:errors) {
|
11
|
+
let(:errors) { ActiveModel::Errors.new(test_model) }
|
12
12
|
|
13
13
|
it 'can record errors' do
|
14
|
-
errors
|
14
|
+
errors.add(:foo, 'bar')
|
15
|
+
expect(errors[:foo]).to eq ['bar']
|
15
16
|
expect(errors.any?).to be(true)
|
16
17
|
end
|
17
18
|
|
@@ -24,13 +25,13 @@ RSpec.describe 'BetterActiveModelErrors' do
|
|
24
25
|
it 'duplicates when copy called' do
|
25
26
|
model = OpenStruct.new
|
26
27
|
|
27
|
-
error =
|
28
|
-
error.
|
29
|
-
expect(error
|
28
|
+
error = ActiveModel::Errors.new(model)
|
29
|
+
error.add(:code, 'error')
|
30
|
+
expect(error[:code]).to eq ['error']
|
30
31
|
|
31
|
-
other =
|
32
|
-
other.
|
32
|
+
other = ActiveModel::Errors.new(model)
|
33
|
+
other.add(:code, 'warning')
|
33
34
|
error.copy!(other)
|
34
|
-
expect(error
|
35
|
+
expect(error[:code]).to eq ['warning']
|
35
36
|
end
|
36
37
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -26,9 +26,9 @@ end
|
|
26
26
|
require 'lev'
|
27
27
|
require 'byebug'
|
28
28
|
|
29
|
-
require '
|
29
|
+
require 'open_stax_transaction_retry'
|
30
30
|
|
31
|
-
|
31
|
+
OpenStaxTransactionRetry.apply_activerecord_patch
|
32
32
|
|
33
33
|
Dir[(File.expand_path('../support', __FILE__)) + ("/**/*.rb")].each { |f| require f }
|
34
34
|
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lev
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 12.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- JP Slavinsky
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: actionpack
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,63 +25,63 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: active_attr
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: activejob
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :runtime
|
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: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: activemodel
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '6.1'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '6.1'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: activerecord
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '4.2'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
82
|
+
version: '4.2'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: hashie
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
@@ -95,7 +95,7 @@ dependencies:
|
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: openstax_transaction_retry
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - ">="
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: transaction_isolation
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - ">="
|
@@ -137,21 +137,21 @@ dependencies:
|
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
140
|
+
name: jobba
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
143
|
- - ">="
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: '0'
|
145
|
+
version: '2.0'
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: '0'
|
152
|
+
version: '2.0'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
154
|
+
name: rake
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
157
|
- - ">="
|
@@ -165,7 +165,7 @@ dependencies:
|
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
|
-
name:
|
168
|
+
name: rspec
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
170
170
|
requirements:
|
171
171
|
- - ">="
|
@@ -179,19 +179,19 @@ dependencies:
|
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0'
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
|
-
name:
|
182
|
+
name: sqlite3
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
185
|
- - ">="
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: '
|
187
|
+
version: '0'
|
188
188
|
type: :development
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
192
|
- - ">="
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: '
|
194
|
+
version: '0'
|
195
195
|
description: Ride the rails but don't touch them.
|
196
196
|
email:
|
197
197
|
- jps@kindlinglabs.com
|
@@ -206,7 +206,6 @@ files:
|
|
206
206
|
- lib/lev/active_job.rb
|
207
207
|
- lib/lev/active_job/base.rb
|
208
208
|
- lib/lev/active_job/configured_job.rb
|
209
|
-
- lib/lev/better_active_model_errors.rb
|
210
209
|
- lib/lev/delegate_to_routine.rb
|
211
210
|
- lib/lev/error.rb
|
212
211
|
- lib/lev/error_transferer.rb
|
@@ -227,7 +226,7 @@ files:
|
|
227
226
|
- lib/lev/utilities.rb
|
228
227
|
- lib/lev/version.rb
|
229
228
|
- spec/active_job_routines_spec.rb
|
230
|
-
- spec/
|
229
|
+
- spec/active_model_errors_spec.rb
|
231
230
|
- spec/create_sprocket_spec.rb
|
232
231
|
- spec/deep_merge_spec.rb
|
233
232
|
- spec/delegates_to_spec.rb
|
@@ -250,7 +249,7 @@ homepage: http://github.com/lml/lev
|
|
250
249
|
licenses:
|
251
250
|
- MIT
|
252
251
|
metadata: {}
|
253
|
-
post_install_message:
|
252
|
+
post_install_message:
|
254
253
|
rdoc_options: []
|
255
254
|
require_paths:
|
256
255
|
- lib
|
@@ -265,28 +264,28 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
265
264
|
- !ruby/object:Gem::Version
|
266
265
|
version: '0'
|
267
266
|
requirements: []
|
268
|
-
rubygems_version: 3.
|
269
|
-
signing_key:
|
267
|
+
rubygems_version: 3.4.6
|
268
|
+
signing_key:
|
270
269
|
specification_version: 4
|
271
270
|
summary: Ride the rails but don't touch them.
|
272
271
|
test_files:
|
273
272
|
- spec/active_job_routines_spec.rb
|
274
|
-
- spec/
|
275
|
-
- spec/spec_helper.rb
|
276
|
-
- spec/sprocket_spec.rb
|
273
|
+
- spec/active_model_errors_spec.rb
|
277
274
|
- spec/create_sprocket_spec.rb
|
278
|
-
- spec/outputs_spec.rb
|
279
275
|
- spec/deep_merge_spec.rb
|
276
|
+
- spec/delegates_to_spec.rb
|
277
|
+
- spec/outputs_spec.rb
|
278
|
+
- spec/paramify_handler_spec.rb
|
279
|
+
- spec/routine_spec.rb
|
280
|
+
- spec/spec_helper.rb
|
280
281
|
- spec/sprocket_handler_spec.rb
|
282
|
+
- spec/sprocket_spec.rb
|
281
283
|
- spec/statused_routines_spec.rb
|
282
|
-
- spec/better_active_model_errors_spec.rb
|
283
|
-
- spec/routine_spec.rb
|
284
|
-
- spec/support/sprocket_handler.rb
|
285
284
|
- spec/support/create_sprocket.rb
|
286
285
|
- spec/support/delegated_routine.rb
|
287
|
-
- spec/support/
|
286
|
+
- spec/support/delegating_routine.rb
|
288
287
|
- spec/support/paramify_handler_a.rb
|
289
288
|
- spec/support/paramify_handler_b.rb
|
290
|
-
- spec/support/
|
289
|
+
- spec/support/sprocket.rb
|
290
|
+
- spec/support/sprocket_handler.rb
|
291
291
|
- spec/transaction_spec.rb
|
292
|
-
- spec/delegates_to_spec.rb
|
@@ -1,421 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
|
3
|
-
require 'active_support/core_ext/array/wrap'
|
4
|
-
require 'active_support/core_ext/array/conversions'
|
5
|
-
require 'active_support/core_ext/string/inflections'
|
6
|
-
require 'active_support/core_ext/object/blank'
|
7
|
-
require 'active_support/core_ext/hash/reverse_merge'
|
8
|
-
require 'active_support/ordered_hash'
|
9
|
-
|
10
|
-
module Lev
|
11
|
-
# == Better Errors
|
12
|
-
#
|
13
|
-
# Same as ActiveModel::Errors but also retains error types
|
14
|
-
#
|
15
|
-
# Provides a modified +OrderedHash+ that you can include in your object
|
16
|
-
# for handling error messages and interacting with Action Pack helpers.
|
17
|
-
#
|
18
|
-
# A minimal implementation could be:
|
19
|
-
#
|
20
|
-
# class Person
|
21
|
-
#
|
22
|
-
# # Required dependency for ActiveModel::Errors
|
23
|
-
# extend ActiveModel::Naming
|
24
|
-
#
|
25
|
-
# def initialize
|
26
|
-
# @errors = ActiveModel::Errors.new(self)
|
27
|
-
# end
|
28
|
-
#
|
29
|
-
# attr_accessor :name
|
30
|
-
# attr_reader :errors
|
31
|
-
#
|
32
|
-
# def validate!
|
33
|
-
# errors.add(:name, "can not be nil") if name == nil
|
34
|
-
# end
|
35
|
-
#
|
36
|
-
# # The following methods are needed to be minimally implemented
|
37
|
-
#
|
38
|
-
# def read_attribute_for_validation(attr)
|
39
|
-
# send(attr)
|
40
|
-
# end
|
41
|
-
#
|
42
|
-
# def Person.human_attribute_name(attr, options = {})
|
43
|
-
# attr
|
44
|
-
# end
|
45
|
-
#
|
46
|
-
# def Person.lookup_ancestors
|
47
|
-
# [self]
|
48
|
-
# end
|
49
|
-
#
|
50
|
-
# end
|
51
|
-
#
|
52
|
-
# The last three methods are required in your object for Errors to be
|
53
|
-
# able to generate error messages correctly and also handle multiple
|
54
|
-
# languages. Of course, if you extend your object with ActiveModel::Translation
|
55
|
-
# you will not need to implement the last two. Likewise, using
|
56
|
-
# ActiveModel::Validations will handle the validation related methods
|
57
|
-
# for you.
|
58
|
-
#
|
59
|
-
# The above allows you to do:
|
60
|
-
#
|
61
|
-
# p = Person.new
|
62
|
-
# p.validate! # => ["can not be nil"]
|
63
|
-
# p.errors.full_messages # => ["name can not be nil"]
|
64
|
-
# # etc..
|
65
|
-
class BetterActiveModelErrors
|
66
|
-
include Enumerable
|
67
|
-
|
68
|
-
CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
|
69
|
-
|
70
|
-
attr_reader :messages
|
71
|
-
attr_reader :types
|
72
|
-
|
73
|
-
# Pass in the instance of the object that is using the errors object.
|
74
|
-
#
|
75
|
-
# class Person
|
76
|
-
# def initialize
|
77
|
-
# @errors = ActiveModel::Errors.new(self)
|
78
|
-
# end
|
79
|
-
# end
|
80
|
-
def initialize(base)
|
81
|
-
@base = base
|
82
|
-
@types = ActiveSupport::OrderedHash.new
|
83
|
-
@messages = ActiveSupport::OrderedHash.new
|
84
|
-
end
|
85
|
-
|
86
|
-
# copy & details are needed to match `ActiveModel::Errors` interface
|
87
|
-
def copy!(other)
|
88
|
-
initialize_dup(other)
|
89
|
-
end
|
90
|
-
def details
|
91
|
-
{}
|
92
|
-
end
|
93
|
-
|
94
|
-
def initialize_dup(other)
|
95
|
-
@types = other.types.dup
|
96
|
-
@messages = other.messages.dup
|
97
|
-
end
|
98
|
-
|
99
|
-
# Backport dup from 1.9 so that #initialize_dup gets called
|
100
|
-
unless Object.respond_to?(:initialize_dup, true)
|
101
|
-
def dup # :nodoc:
|
102
|
-
copy = super
|
103
|
-
copy.initialize_dup(self)
|
104
|
-
copy
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Clear the messages
|
109
|
-
def clear
|
110
|
-
types.clear
|
111
|
-
messages.clear
|
112
|
-
end
|
113
|
-
|
114
|
-
# Do the error messages include an error with key +error+?
|
115
|
-
def include?(error)
|
116
|
-
(v = messages[error.to_sym]) && v.any?
|
117
|
-
end
|
118
|
-
alias :has_key? :include?
|
119
|
-
|
120
|
-
# Get messages for +key+
|
121
|
-
def get(key)
|
122
|
-
messages[key.to_sym]
|
123
|
-
end
|
124
|
-
|
125
|
-
def get_type(key)
|
126
|
-
types[key.to_sym]
|
127
|
-
end
|
128
|
-
|
129
|
-
# Set messages for +key+ to +value+
|
130
|
-
def set(key, value)
|
131
|
-
types[key.to_sym] = (value == [] ? [] : (value.is_a?(Symbol) ? value : nil))
|
132
|
-
messages[key.to_sym] = value
|
133
|
-
end
|
134
|
-
|
135
|
-
# Delete messages for +key+
|
136
|
-
def delete(key)
|
137
|
-
key = key.to_sym
|
138
|
-
types.delete(key)
|
139
|
-
messages.delete(key)
|
140
|
-
end
|
141
|
-
|
142
|
-
# When passed a symbol or a name of a method, returns an array of errors
|
143
|
-
# for the method.
|
144
|
-
#
|
145
|
-
# p.errors[:name] # => ["can not be nil"]
|
146
|
-
# p.errors['name'] # => ["can not be nil"]
|
147
|
-
def [](attribute)
|
148
|
-
get(attribute.to_sym) || set(attribute.to_sym, [])
|
149
|
-
end
|
150
|
-
|
151
|
-
# Adds to the supplied attribute the supplied error message.
|
152
|
-
#
|
153
|
-
# p.errors[:name] = "must be set"
|
154
|
-
# p.errors[:name] # => ['must be set']
|
155
|
-
def []=(attribute, error)
|
156
|
-
self[attribute] << error
|
157
|
-
end
|
158
|
-
|
159
|
-
# Iterates through each error key, value pair in the error messages hash.
|
160
|
-
# Yields the attribute and the error for that attribute. If the attribute
|
161
|
-
# has more than one error message, yields once for each error message.
|
162
|
-
#
|
163
|
-
# p.errors.add(:name, "can't be blank")
|
164
|
-
# p.errors.each do |attribute, errors_array|
|
165
|
-
# # Will yield :name and "can't be blank"
|
166
|
-
# end
|
167
|
-
#
|
168
|
-
# p.errors.add(:name, "must be specified")
|
169
|
-
# p.errors.each do |attribute, errors_array|
|
170
|
-
# # Will yield :name and "can't be blank"
|
171
|
-
# # then yield :name and "must be specified"
|
172
|
-
# end
|
173
|
-
def each
|
174
|
-
messages.each_key do |attribute|
|
175
|
-
self[attribute].each { |error| yield attribute, error }
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
def each_with_type_and_message
|
180
|
-
types.each_key do |attribute|
|
181
|
-
for ii in 0..self.types[attribute].size-1
|
182
|
-
yield attribute, self.types[attribute][ii], self.messages[attribute][ii]
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
# Returns the number of error messages.
|
188
|
-
#
|
189
|
-
# p.errors.add(:name, "can't be blank")
|
190
|
-
# p.errors.size # => 1
|
191
|
-
# p.errors.add(:name, "must be specified")
|
192
|
-
# p.errors.size # => 2
|
193
|
-
def size
|
194
|
-
values.flatten.size
|
195
|
-
end
|
196
|
-
|
197
|
-
# Returns all message values
|
198
|
-
def values
|
199
|
-
messages.values
|
200
|
-
end
|
201
|
-
|
202
|
-
# Returns all message keys
|
203
|
-
def keys
|
204
|
-
messages.keys
|
205
|
-
end
|
206
|
-
|
207
|
-
# Returns an array of error messages, with the attribute name included
|
208
|
-
#
|
209
|
-
# p.errors.add(:name, "can't be blank")
|
210
|
-
# p.errors.add(:name, "must be specified")
|
211
|
-
# p.errors.to_a # => ["name can't be blank", "name must be specified"]
|
212
|
-
def to_a
|
213
|
-
full_messages
|
214
|
-
end
|
215
|
-
|
216
|
-
# Returns the number of error messages.
|
217
|
-
# p.errors.add(:name, "can't be blank")
|
218
|
-
# p.errors.count # => 1
|
219
|
-
# p.errors.add(:name, "must be specified")
|
220
|
-
# p.errors.count # => 2
|
221
|
-
def count
|
222
|
-
to_a.size
|
223
|
-
end
|
224
|
-
|
225
|
-
# Returns true if no errors are found, false otherwise.
|
226
|
-
# If the error message is a string it can be empty.
|
227
|
-
def empty?
|
228
|
-
all? { |k, v| v && v.empty? && !v.is_a?(String) }
|
229
|
-
end
|
230
|
-
alias_method :blank?, :empty?
|
231
|
-
|
232
|
-
# Returns an xml formatted representation of the Errors hash.
|
233
|
-
#
|
234
|
-
# p.errors.add(:name, "can't be blank")
|
235
|
-
# p.errors.add(:name, "must be specified")
|
236
|
-
# p.errors.to_xml
|
237
|
-
# # =>
|
238
|
-
# # <?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
239
|
-
# # <errors>
|
240
|
-
# # <error>name can't be blank</error>
|
241
|
-
# # <error>name must be specified</error>
|
242
|
-
# # </errors>
|
243
|
-
def to_xml(options={})
|
244
|
-
to_a.to_xml options.reverse_merge(:root => "errors", :skip_types => true)
|
245
|
-
end
|
246
|
-
|
247
|
-
# Returns an ActiveSupport::OrderedHash that can be used as the JSON representation for this object.
|
248
|
-
def as_json(options=nil)
|
249
|
-
to_hash
|
250
|
-
end
|
251
|
-
|
252
|
-
def to_hash
|
253
|
-
messages.dup
|
254
|
-
end
|
255
|
-
|
256
|
-
def to_s
|
257
|
-
inspect
|
258
|
-
end
|
259
|
-
|
260
|
-
# Adds +message+ to the error messages on +attribute+. More than one error can be added to the same
|
261
|
-
# +attribute+.
|
262
|
-
# If no +message+ is supplied, <tt>:invalid</tt> is assumed.
|
263
|
-
#
|
264
|
-
# If +message+ is a symbol, it will be translated using the appropriate scope (see +translate_error+).
|
265
|
-
# If +message+ is a proc, it will be called, allowing for things like <tt>Time.now</tt> to be used within an error.
|
266
|
-
def add(attribute, message = nil, options = {})
|
267
|
-
normalized_message = normalize_message(attribute, message, options)
|
268
|
-
if options[:strict]
|
269
|
-
raise ActiveModel::StrictValidationFailed, full_message(attribute, normalized_message)
|
270
|
-
end
|
271
|
-
|
272
|
-
self[attribute] << normalized_message
|
273
|
-
self.types[attribute.to_sym] << message.try(:to_sym)
|
274
|
-
end
|
275
|
-
|
276
|
-
# Will add an error message to each of the attributes in +attributes+ that is empty.
|
277
|
-
def add_on_empty(attributes, options = {})
|
278
|
-
[attributes].flatten.each do |attribute|
|
279
|
-
value = @base.send(:read_attribute_for_validation, attribute)
|
280
|
-
is_empty = value.respond_to?(:empty?) ? value.empty? : false
|
281
|
-
add(attribute, :empty, options) if value.nil? || is_empty
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
# Will add an error message to each of the attributes in +attributes+ that is blank (using Object#blank?).
|
286
|
-
def add_on_blank(attributes, options = {})
|
287
|
-
[attributes].flatten.each do |attribute|
|
288
|
-
value = @base.send(:read_attribute_for_validation, attribute)
|
289
|
-
add(attribute, :blank, options) if value.blank?
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
# Returns true if an error on the attribute with the given message is present, false otherwise.
|
294
|
-
# +message+ is treated the same as for +add+.
|
295
|
-
# p.errors.add :name, :blank
|
296
|
-
# p.errors.added? :name, :blank # => true
|
297
|
-
def added?(attribute, message = nil, options = {})
|
298
|
-
message = normalize_message(attribute, message, options)
|
299
|
-
self[attribute].include? message
|
300
|
-
end
|
301
|
-
|
302
|
-
# Returns all the full error messages in an array.
|
303
|
-
#
|
304
|
-
# class Company
|
305
|
-
# validates_presence_of :name, :address, :email
|
306
|
-
# validates_length_of :name, :in => 5..30
|
307
|
-
# end
|
308
|
-
#
|
309
|
-
# company = Company.create(:address => '123 First St.')
|
310
|
-
# company.errors.full_messages # =>
|
311
|
-
# ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Email can't be blank"]
|
312
|
-
def full_messages
|
313
|
-
map { |attribute, message| full_message(attribute, message) }
|
314
|
-
end
|
315
|
-
|
316
|
-
# Returns a full message for a given attribute.
|
317
|
-
#
|
318
|
-
# company.errors.full_message(:name, "is invalid") # =>
|
319
|
-
# "Name is invalid"
|
320
|
-
def full_message(attribute, message)
|
321
|
-
self.class.full_message(@base, attribute, message)
|
322
|
-
end
|
323
|
-
|
324
|
-
def self.full_message(model, attribute, message)
|
325
|
-
return message if attribute == :base
|
326
|
-
attr_name = attribute.to_s.gsub('.', '_').humanize
|
327
|
-
attr_name = model.class.human_attribute_name(attribute, default: attr_name)
|
328
|
-
I18n.t(:"errors.format", {
|
329
|
-
default: "%{attribute} %{message}",
|
330
|
-
attribute: attr_name,
|
331
|
-
message: message
|
332
|
-
})
|
333
|
-
end
|
334
|
-
|
335
|
-
# Translates an error message in its default scope
|
336
|
-
# (<tt>activemodel.errors.messages</tt>).
|
337
|
-
#
|
338
|
-
# Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>,
|
339
|
-
# if it's not there, it's looked up in <tt>models.MODEL.MESSAGE</tt> and if that is not
|
340
|
-
# there also, it returns the translation of the default message
|
341
|
-
# (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model name,
|
342
|
-
# translated attribute name and the value are available for interpolation.
|
343
|
-
#
|
344
|
-
# When using inheritance in your models, it will check all the inherited
|
345
|
-
# models too, but only if the model itself hasn't been found. Say you have
|
346
|
-
# <tt>class Admin < User; end</tt> and you wanted the translation for
|
347
|
-
# the <tt>:blank</tt> error message for the <tt>title</tt> attribute,
|
348
|
-
# it looks for these translations:
|
349
|
-
#
|
350
|
-
# * <tt>activemodel.errors.models.admin.attributes.title.blank</tt>
|
351
|
-
# * <tt>activemodel.errors.models.admin.blank</tt>
|
352
|
-
# * <tt>activemodel.errors.models.user.attributes.title.blank</tt>
|
353
|
-
# * <tt>activemodel.errors.models.user.blank</tt>
|
354
|
-
# * any default you provided through the +options+ hash (in the <tt>activemodel.errors</tt> scope)
|
355
|
-
# * <tt>activemodel.errors.messages.blank</tt>
|
356
|
-
# * <tt>errors.attributes.title.blank</tt>
|
357
|
-
# * <tt>errors.messages.blank</tt>
|
358
|
-
#
|
359
|
-
def generate_message(attribute, type = :invalid, options = {})
|
360
|
-
self.class.generate_message(@base, attribute, type, options)
|
361
|
-
end
|
362
|
-
|
363
|
-
# TODO maybe don't need this method split out any more?
|
364
|
-
def self.generate_message(model, attribute, type = :invalid, options = {})
|
365
|
-
type = options.delete(:message) if options[:message].is_a?(Symbol)
|
366
|
-
attribute = attribute.to_sym
|
367
|
-
if model.class.respond_to?(:i18n_scope)
|
368
|
-
defaults = model.class.lookup_ancestors.map do |klass|
|
369
|
-
[ :"#{model.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
|
370
|
-
:"#{model.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
|
371
|
-
end
|
372
|
-
else
|
373
|
-
defaults = []
|
374
|
-
end
|
375
|
-
|
376
|
-
defaults << options.delete(:message)
|
377
|
-
defaults << :"#{model.class.i18n_scope}.errors.messages.#{type}" if model.class.respond_to?(:i18n_scope)
|
378
|
-
defaults << :"errors.attributes.#{attribute}.#{type}"
|
379
|
-
defaults << :"errors.messages.#{type}"
|
380
|
-
|
381
|
-
defaults.compact!
|
382
|
-
defaults.flatten!
|
383
|
-
|
384
|
-
key = defaults.shift
|
385
|
-
value = (attribute != :base ? model.send(:read_attribute_for_validation, attribute) : nil)
|
386
|
-
|
387
|
-
options = {
|
388
|
-
:default => defaults,
|
389
|
-
:model => model.class.model_name.human,
|
390
|
-
:attribute => model.class.human_attribute_name(attribute),
|
391
|
-
:value => value
|
392
|
-
}.merge(options)
|
393
|
-
|
394
|
-
I18n.translate(key, options)
|
395
|
-
end
|
396
|
-
|
397
|
-
private
|
398
|
-
def normalize_message(attribute, message, options)
|
399
|
-
message ||= :invalid
|
400
|
-
|
401
|
-
if message.is_a?(Symbol)
|
402
|
-
generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS))
|
403
|
-
elsif message.is_a?(Proc)
|
404
|
-
message.call
|
405
|
-
else
|
406
|
-
message
|
407
|
-
end
|
408
|
-
end
|
409
|
-
end
|
410
|
-
|
411
|
-
class StrictValidationFailed < StandardError
|
412
|
-
end
|
413
|
-
end
|
414
|
-
|
415
|
-
module ActiveModel
|
416
|
-
module Validations
|
417
|
-
def errors
|
418
|
-
@errors ||= Lev::BetterActiveModelErrors.new(self)
|
419
|
-
end
|
420
|
-
end
|
421
|
-
end
|