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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55aaacdd314e854a95aca72c83634ece746a7c31a7d3e58301a5fda92c9b2707
4
- data.tar.gz: 70e39fd14316c98bcbfb600cbc7b1e16591104a799009413cff04c6288d16fe8
3
+ metadata.gz: 91cfccd8caeadd3b09908be75b68575ecdb340635b659308698ab69a44d6e182
4
+ data.tar.gz: 8a52a8bf9234772fe4f8a300db88052ef0ad41f3646cd7a7dd2b8b196cc7ad7f
5
5
  SHA512:
6
- metadata.gz: 1ac1927d091c9a93cb365bd7b2cd795194a4146a981f049f4400f086a69d1c34d5c5a8388aee7dee6dde887820a42ca9bbfad21a14617267dfb0201279f4d143
7
- data.tar.gz: e2a946a5cbddc28a853ca4666d669cc7adee771ad2ce9adf3e482691b6db7a29f047f5ed407ef27f2a2de1fbbfdb0588c9650ee8037ba246d897f9302f229053
6
+ metadata.gz: b0320860ee577c911f99d5ed1c7c05cc271a585dfb9cabec70a05fb0981e02a879f709a6802e56c5ba64d116b204cc6457786b4dbd89fe6bcdfdca8a329d0c72
7
+ data.tar.gz: 7475544cf746a002b080aa021bef5e3975d2a45df99e9d37a1c3b6eb6cf08145d5fd96086efa20c8df93f5cdba521a4f1d3694c025c918dbdd835e332b4fc3da
data/README.md CHANGED
@@ -1,4 +1,235 @@
1
- # README
1
+ # Better Validations
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/better_validations.svg)](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 s`.
244
+ 5. Run `rails db:migrate` to run migrations for test models.
14
245
 
15
- 6. Open `http://localhost:3000/` in browser.
246
+ 6. Run `rspec` to check tests.
@@ -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 do |field, _|
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
@@ -1,3 +1,3 @@
1
1
  module BetterValidations
2
- VERSION = '0.1.2'.freeze
2
+ VERSION = '0.1.3'.freeze
3
3
  end
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.2
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-14 00:00:00.000000000 Z
11
+ date: 2020-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails