better_validations 0.1.2 → 0.1.3
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.
- checksums.yaml +4 -4
- data/README.md +235 -4
- data/lib/better_validations.rb +0 -69
- data/lib/better_validations/errors.rb +1 -11
- data/lib/better_validations/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 91cfccd8caeadd3b09908be75b68575ecdb340635b659308698ab69a44d6e182
|
4
|
+
data.tar.gz: 8a52a8bf9234772fe4f8a300db88052ef0ad41f3646cd7a7dd2b8b196cc7ad7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0320860ee577c911f99d5ed1c7c05cc271a585dfb9cabec70a05fb0981e02a879f709a6802e56c5ba64d116b204cc6457786b4dbd89fe6bcdfdca8a329d0c72
|
7
|
+
data.tar.gz: 7475544cf746a002b080aa021bef5e3975d2a45df99e9d37a1c3b6eb6cf08145d5fd96086efa20c8df93f5cdba521a4f1d3694c025c918dbdd835e332b4fc3da
|
data/README.md
CHANGED
@@ -1,4 +1,235 @@
|
|
1
|
-
#
|
1
|
+
# Better Validations
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/better_validations)
|
4
|
+
|
5
|
+
Better Validations is an extension for default Rails validations with useful features.
|
6
|
+
|
7
|
+
## Table of contents
|
8
|
+
|
9
|
+
- [Installation](#installation)
|
10
|
+
- [Features](#features)
|
11
|
+
- [Structured error messages](#structured-error-messages)
|
12
|
+
- [Nested validations](#nested-validations)
|
13
|
+
- [Merge error messages from multiple validators](#merge-error-messages-from-multiple-validators)
|
14
|
+
- [Best practices](#best-practices)
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add to your Gemfile:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem 'better_validations'
|
22
|
+
```
|
23
|
+
|
24
|
+
Run:
|
25
|
+
|
26
|
+
```bash
|
27
|
+
bundle install
|
28
|
+
```
|
29
|
+
|
30
|
+
## Features
|
31
|
+
|
32
|
+
### Structured error messages
|
33
|
+
|
34
|
+
Better Validations provides a way to get error messages from an active record keeping structure of nested objects represented by relations such as `belongs_to`, `has_one`, `has_many` instead of a flat structure. Just call:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
active_record.errors.detailed_messages
|
38
|
+
```
|
39
|
+
|
40
|
+
This calling returns a hash such as:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
{
|
44
|
+
attribute_one: ['Error 1', 'Error 2'],
|
45
|
+
attribute_two: ['Error 3'],
|
46
|
+
nested_object: {
|
47
|
+
attribute_three: ['Error 4']
|
48
|
+
},
|
49
|
+
nested_objects: [
|
50
|
+
{
|
51
|
+
attribute_four: ['Error 5']
|
52
|
+
}
|
53
|
+
]
|
54
|
+
}
|
55
|
+
```
|
56
|
+
|
57
|
+
Instead of default `active_record.errors.messages`:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
{
|
61
|
+
attribute_one: ['Error 1', 'Error 2'],
|
62
|
+
attribute_two: ['Error 3'],
|
63
|
+
'nested_object.attribute_three': ['Error 4'],
|
64
|
+
'nested_objects.attribute_four': ['Error 5']
|
65
|
+
}
|
66
|
+
```
|
67
|
+
|
68
|
+
You can wrap attributes in some key by passing optional `wrap_attributes_to` argument in all levels of nesting:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
active_record.errors.detailed_messages(
|
72
|
+
wrap_attributes_to: :fields
|
73
|
+
)
|
74
|
+
|
75
|
+
{
|
76
|
+
fields: {
|
77
|
+
attribute_one: ['Error 1', 'Error 2'],
|
78
|
+
attribute_two: ['Error 3']
|
79
|
+
},
|
80
|
+
nested_object: {
|
81
|
+
fields: {
|
82
|
+
attribute_three: ['Error 4']
|
83
|
+
}
|
84
|
+
},
|
85
|
+
nested_objects: [
|
86
|
+
{
|
87
|
+
fields: {
|
88
|
+
attribute_four: ['Error 5']
|
89
|
+
}
|
90
|
+
}
|
91
|
+
]
|
92
|
+
}
|
93
|
+
```
|
94
|
+
|
95
|
+
This is useful if you have validations both on the relation and in the nested object of this relation:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
# Try to create an object with a nested list where must be at least 2 elements
|
99
|
+
object = SomeModel.create(nested_objects_attributes: [{ attribute_one: nil }])
|
100
|
+
object.errors.detailed_messages(wrap_attributes_to: :fields)
|
101
|
+
|
102
|
+
{
|
103
|
+
fields: {
|
104
|
+
nested_objects: ['too few nested objects. Must be at least 2']
|
105
|
+
},
|
106
|
+
nested_objects: [
|
107
|
+
{
|
108
|
+
fields: {
|
109
|
+
attribute_one: "can't be blank"
|
110
|
+
}
|
111
|
+
}
|
112
|
+
]
|
113
|
+
}
|
114
|
+
```
|
115
|
+
|
116
|
+
**Note!** The order of objects in a nested list returned by `detailed_messages` can be different from the order in a passed nested attributes. You can match objects by identifiers or pass a `client_id` attribute for objects that have not yet been created:
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
object.update(nested_objects_attributes: [
|
120
|
+
{
|
121
|
+
id: 1,
|
122
|
+
client_id: 'identifier_one'
|
123
|
+
attribute_one: nil,
|
124
|
+
attribute_two: 'filled'
|
125
|
+
},
|
126
|
+
{
|
127
|
+
client_id: 'identifier_two',
|
128
|
+
attribute_one: 'filled',
|
129
|
+
attribute_two: nil
|
130
|
+
}
|
131
|
+
])
|
132
|
+
|
133
|
+
object.errors.detailed_messages
|
134
|
+
|
135
|
+
{
|
136
|
+
nested_objects: [
|
137
|
+
{
|
138
|
+
{
|
139
|
+
id: 1,
|
140
|
+
client_id: 'identifier_one'
|
141
|
+
attribute_one: ["can't be blank"]
|
142
|
+
},
|
143
|
+
{
|
144
|
+
client_id: 'identifier_two',
|
145
|
+
attribute_two: ["can't be blank"]
|
146
|
+
}
|
147
|
+
}
|
148
|
+
]
|
149
|
+
}
|
150
|
+
```
|
151
|
+
|
152
|
+
### Nested validations
|
153
|
+
|
154
|
+
Better Validation provides the ability to validate nested objects in separated validators with included `ActiveModel::Validations`.
|
155
|
+
|
156
|
+
Just include `BetterValidations::Validator` instead of `ActiveModel::Validations` and you will can to validate nested objects with the other validator by calling a `validate_nested` method:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
class SomeModelValidator
|
160
|
+
include BetterValidations::Validator
|
161
|
+
attr_accessor :nested_object
|
162
|
+
validate_nested :nested_object, NestedObjectValidator
|
163
|
+
end
|
164
|
+
|
165
|
+
class NestedObjectValidator
|
166
|
+
include BetterValidations::Validator
|
167
|
+
attr_accessor :attribute_one
|
168
|
+
validates_presence_of :attribute_one
|
169
|
+
end
|
170
|
+
|
171
|
+
validator = SomeModelValidator.new(nested_object: { attribute_one: nil })
|
172
|
+
validator.valid? # false
|
173
|
+
validator.errors.detailed_messages
|
174
|
+
|
175
|
+
{ nested_object: { attribute_one: ["can't be blank"] } }
|
176
|
+
```
|
177
|
+
|
178
|
+
You also can validate active record object or `ActionController::Parameters` with nested objects by passing them to the validator:
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
object = SomeModel.new(nested_object: NestedObject.new(attribute_one: nil))
|
182
|
+
# OR
|
183
|
+
object = ActionController::Parameters.new(nested_object: { attribute_one: nil })
|
184
|
+
|
185
|
+
validator = SomeModelValidator.new(object)
|
186
|
+
```
|
187
|
+
|
188
|
+
### Merge error messages from multiple validators
|
189
|
+
|
190
|
+
Better Validations provides the ability to merge validators in order to get merged detailed errors.
|
191
|
+
|
192
|
+
Useful when you needs to get errors from multiple validators or if a part of validations implemented inside a model. Usage:
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
validator = validator_one.merge(validator_two, object, ...)
|
196
|
+
validator.valid?
|
197
|
+
validator.errors.detailed_messages
|
198
|
+
```
|
199
|
+
|
200
|
+
## Best practices
|
201
|
+
|
202
|
+
### Base class for all validators
|
203
|
+
|
204
|
+
Create a base `ApplicationValidator` class for all validators in the project. By analogy with `ApplicationRecord` and `ApplicationController`:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
class ApplicationValidator
|
208
|
+
include BetterValidations::Validator
|
209
|
+
end
|
210
|
+
|
211
|
+
class SomeModelValidator < ApplicationValidator
|
212
|
+
end
|
213
|
+
```
|
214
|
+
|
215
|
+
This will allow you to easily add common functionality to the validators. For example, add automatic parsing of keys with `_attributes` suffix to validator properties in order to support format of `accepts_nested_attributes_for` parameters:
|
216
|
+
|
217
|
+
```ruby
|
218
|
+
class ApplicationValidator
|
219
|
+
include BetterValidations::Validator
|
220
|
+
|
221
|
+
def self.validate_nested(nested_name, validator_class)
|
222
|
+
define_attributes_accessor(nested_name)
|
223
|
+
bind_validator(nested_name, validator_class)
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.define_attributes_accessor(nested_name)
|
227
|
+
setter_name = "#{nested_name}_attributes="
|
228
|
+
define_method(setter_name) { |value| set_value(nested_name, value) }
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
```
|
2
233
|
|
3
234
|
## Development
|
4
235
|
|
@@ -8,8 +239,8 @@
|
|
8
239
|
|
9
240
|
3. Feel `.env` file by actual values of DATABASE_USER and DATABASE_PASSWORD.
|
10
241
|
|
11
|
-
4. Run `rails db:create
|
242
|
+
4. Run `rails db:create` to create a database.
|
12
243
|
|
13
|
-
5. Run `rails
|
244
|
+
5. Run `rails db:migrate` to run migrations for test models.
|
14
245
|
|
15
|
-
6.
|
246
|
+
6. Run `rspec` to check tests.
|
data/lib/better_validations.rb
CHANGED
@@ -7,76 +7,7 @@ require_relative 'better_validations/nested_validator'
|
|
7
7
|
require_relative 'better_validations/validator'
|
8
8
|
require_relative 'better_validations/validators_list'
|
9
9
|
|
10
|
-
# 1. A module provides a way to get error messages from an active record
|
11
|
-
# keeping structure of nested objects represented by relations
|
12
|
-
# such as belongs_to, has_one, has_many instead of a flat structure. Just call:
|
13
|
-
#
|
14
|
-
# active_record.errors.detailed_messages
|
15
|
-
#
|
16
|
-
# This calling returns a hash such as:
|
17
|
-
#
|
18
|
-
# { field_one: ['Error 1', 'Error 2'],
|
19
|
-
# field_two: ['Error'],
|
20
|
-
# nested_object: { field: ['Error'] },
|
21
|
-
# nested_list: [{ field: ['Error'] }] }
|
22
|
-
#
|
23
|
-
# A "detailed_messages" method has a "wrap_attributes_to" parameter.
|
24
|
-
# You can use it to wrap all attributes except relations by passed key:
|
25
|
-
#
|
26
|
-
# active_record.errors.detailed_messages(wrap_attributes_to: :fields)
|
27
|
-
# { fields: { field_one: ['Error'], field_two: ['Error'] },
|
28
|
-
# nested_object: { fields: { field: ['Error'] } } }
|
29
|
-
#
|
30
|
-
# This module also provides other features.
|
31
|
-
#
|
32
|
-
# 2. Ability to validate nested objects in separated validators with
|
33
|
-
# included ActiveModel::Validations.
|
34
|
-
#
|
35
|
-
# Just include BetterValidations::Validator instead of ActiveModel::Validations
|
36
|
-
# and you will can to validate nested objects with the other validator by
|
37
|
-
# calling a "validate_nested" method:
|
38
|
-
#
|
39
|
-
# class UserValidator
|
40
|
-
# include BetterValidations::Validator
|
41
|
-
#
|
42
|
-
# attr_accessor :email, :password, :personal_info
|
43
|
-
#
|
44
|
-
# validates_presence_of :email, :password
|
45
|
-
# validate_nested :personal_info, PersonalInfoValidator
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# class PersonalInfoValidator
|
49
|
-
# include BetterValidations::Validator
|
50
|
-
#
|
51
|
-
# attr_accessor :first_name, :last_name
|
52
|
-
# validates_presence_of :first_name, :last_name
|
53
|
-
# end
|
54
|
-
#
|
55
|
-
# After that you can validate active record object, hash or
|
56
|
-
# ActionController::Parameters by passing them to the validator.
|
57
|
-
# Keys "#{field}" and "#{field}_attributes" are synonyms and fills
|
58
|
-
# a "#{field}=" attr_accessor:
|
59
|
-
#
|
60
|
-
# user = User.new(email: '', personal_info_attributes: { first_name: '' })
|
61
|
-
# user = User.new(personal_info: PersonalInfo.new(last_name: ''))
|
62
|
-
# user = { email: '', personal_info_attributes: { last_name: '' } }
|
63
|
-
# user = { email: '', personal_info: { last_name: '' } }
|
64
|
-
# user = ActionController::Parameters.new(email: '')
|
65
|
-
#
|
66
|
-
# validator = UserValidator.new(user)
|
67
|
-
# validator.valid?
|
68
|
-
# validator.errors.detailed_messages
|
69
|
-
#
|
70
|
-
# 3. Ability to merge validators in order to get merged detailed errors.
|
71
|
-
# Useful when you needs to get errors from multiple validators
|
72
|
-
# or if a part of validations implemented inside a model. Usage:
|
73
|
-
#
|
74
|
-
# validator = validator_one.merge(validator_two, validator_three, object)
|
75
|
-
# validator.valid?
|
76
|
-
# validator.errors.detailed_messages
|
77
|
-
#
|
78
10
|
module BetterValidations
|
79
|
-
# Your code goes here...
|
80
11
|
end
|
81
12
|
|
82
13
|
ActiveModel::Errors.include BetterValidations::Errors
|
@@ -40,17 +40,7 @@ module BetterValidations::Errors
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def split_messages(messages)
|
43
|
-
messages.partition
|
44
|
-
base_field_name = field.to_s.split('.').first.to_sym
|
45
|
-
|
46
|
-
if @base.class.respond_to?(:reflect_on_association)
|
47
|
-
@base.class.reflect_on_association(base_field_name)
|
48
|
-
else
|
49
|
-
@base.class._validators[base_field_name]&.any? do |validator|
|
50
|
-
validator.is_a? BetterValidations::NestedValidator
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end.map(&:to_h)
|
43
|
+
messages.partition { |field, _| field.to_s.include?('.') }.map(&:to_h)
|
54
44
|
end
|
55
45
|
|
56
46
|
# Converts nested messages to detailed structure with nested objects
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: better_validations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Petr Bazov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-04-
|
11
|
+
date: 2020-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|