errgonomic 0.8.2 → 0.8.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 +3 -1
- data/lib/errgonomic/rails/active_record_optional.rb +50 -4
- data/lib/errgonomic/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6cfa38b0fc666fade921ea48c1301cc51643175a59e82b4f2c50ac3a471e6696
|
|
4
|
+
data.tar.gz: 8294913794e216f90443e3396753a537d1fbbede4bf6e5eab459bdea51691e6e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 395971235a600af1c734db4dddb9aa8363e63d76ce65175ccb40c358e67aeb48e16379b0682177c42ec4f5d90a50fa14a55f7e7b994b0cd8ffe88dda7f89e688
|
|
7
|
+
data.tar.gz: d02c232ea2f79a5a3a04ce3913c1e9c07909655da06b11a5654699be7e371f5a5f8345b5efb9a3be8b40e5de667280b59c49dd2ba9541555faef7ccce8b1ca19
|
data/README.md
CHANGED
|
@@ -201,7 +201,7 @@ end
|
|
|
201
201
|
|
|
202
202
|
When `Rails::Railtie` is defined, Errgonomic installs a Railtie with two opt-in integrations for ActiveRecord:
|
|
203
203
|
|
|
204
|
-
- `include Errgonomic::Rails::ActiveRecordOptional` in a model makes its nullable attributes and `optional: true` associations return `Some(value)` or `None()` instead of a value-or-nil. Every nullable column and optional association is wrapped, with no per-attribute opt-in.
|
|
204
|
+
- `include Errgonomic::Rails::ActiveRecordOptional` in a model makes its nullable attributes and `optional: true` associations return `Some(value)` or `None()` instead of a value-or-nil. Every nullable column and optional association is wrapped, with no per-attribute opt-in. Three kinds of reader stay unwrapped: attributes declared with `encrypts` and singular associations with `accepts_nested_attributes_for`, both of which ActiveRecord's own machinery reads raw, and anything named by `errgonomic_optional_except`.
|
|
205
205
|
|
|
206
206
|
```ruby
|
|
207
207
|
class Credential < ApplicationRecord
|
|
@@ -209,6 +209,8 @@ class Credential < ApplicationRecord
|
|
|
209
209
|
include Errgonomic::Rails::ActiveRecordOptional
|
|
210
210
|
|
|
211
211
|
encrypts :access_secret # also left unwrapped, declared either side of the include
|
|
212
|
+
has_one :rotation_schedule # wrapped: Some(schedule) or None()
|
|
213
|
+
has_one :owner, required: true # left unwrapped: absence is a validation failure
|
|
212
214
|
end
|
|
213
215
|
```
|
|
214
216
|
|
|
@@ -19,9 +19,11 @@ module Errgonomic
|
|
|
19
19
|
# boundary, so an Option can be passed to where/quote.
|
|
20
20
|
# 4. SomeValidator provides a presence-style validation for Option
|
|
21
21
|
# attributes.
|
|
22
|
-
# 5.
|
|
23
|
-
#
|
|
24
|
-
#
|
|
22
|
+
# 5. Readers that ActiveRecord's own machinery reads raw are never
|
|
23
|
+
# wrapped: an attribute declared with encrypts, whose length validator
|
|
24
|
+
# sits outside Model.validators and calls to_s on the value, and a
|
|
25
|
+
# singular association with nested attributes, which are assigned
|
|
26
|
+
# through the reader and ask the value whether it is a new record.
|
|
25
27
|
#
|
|
26
28
|
# errgonomic_optional_except is not on the list: it is configuration, an
|
|
27
29
|
# escape hatch for whatever conflict shows up next, not a semantic
|
|
@@ -33,6 +35,9 @@ module Errgonomic
|
|
|
33
35
|
reflect_on_all_associations(:belongs_to)
|
|
34
36
|
.select { |r| r.options[:optional] }
|
|
35
37
|
.each { |r| errgonomic_wrap_optional(r.name) }
|
|
38
|
+
reflect_on_all_associations(:has_one)
|
|
39
|
+
.reject { |r| r.options[:required] }
|
|
40
|
+
.each { |r| errgonomic_wrap_optional(r.name) }
|
|
36
41
|
end
|
|
37
42
|
|
|
38
43
|
class_methods do
|
|
@@ -61,7 +66,10 @@ module Errgonomic
|
|
|
61
66
|
[]
|
|
62
67
|
end
|
|
63
68
|
|
|
64
|
-
inherited |
|
|
69
|
+
inherited |
|
|
70
|
+
Array(encrypted_attributes).map(&:to_s) |
|
|
71
|
+
Array(try(:errgonomic_optional_exceptions)).map(&:to_s) |
|
|
72
|
+
errgonomic_nested_attribute_associations
|
|
65
73
|
end
|
|
66
74
|
|
|
67
75
|
# A model that keeps value-or-nil throughout, for whatever the
|
|
@@ -116,6 +124,32 @@ module Errgonomic
|
|
|
116
124
|
super.tap { errgonomic_wrap_optional(name) if options[:optional] }
|
|
117
125
|
end
|
|
118
126
|
|
|
127
|
+
# A has_one is absent whenever no row points back at the record, so
|
|
128
|
+
# its reader carries the same absence a nullable column does.
|
|
129
|
+
# required: true is the exception: it asserts the record is there, and
|
|
130
|
+
# absence is a validation failure rather than a value to handle.
|
|
131
|
+
def has_one(name, scope = nil, **options)
|
|
132
|
+
super.tap { errgonomic_wrap_optional(name) unless options[:required] }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Nested attributes are assigned through the public reader, and
|
|
136
|
+
# ActiveRecord asks whatever it finds there whether it is a new
|
|
137
|
+
# record. An absent association has to arrive as nil for that, so a
|
|
138
|
+
# singular association with nested attributes keeps its plain reader.
|
|
139
|
+
def accepts_nested_attributes_for(*names, **options)
|
|
140
|
+
super.tap { errgonomic_unwrap_optionals(*names) }
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# ActiveRecord keeps its own register of these, so the exclusion can be
|
|
144
|
+
# read from there rather than recorded as it goes past.
|
|
145
|
+
def errgonomic_nested_attribute_associations
|
|
146
|
+
return [] unless respond_to?(:nested_attributes_options)
|
|
147
|
+
|
|
148
|
+
nested_attributes_options.keys.map(&:to_s).select do |name|
|
|
149
|
+
%i[has_one belongs_to].include?(reflect_on_association(name)&.macro)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
119
153
|
# Encryption surrounds an attribute with machinery that reads the raw
|
|
120
154
|
# value, including a length validator that calls to_s on it, so a
|
|
121
155
|
# wrapped encrypted attribute cannot be saved. Declaring encrypts
|
|
@@ -223,6 +257,18 @@ class Object
|
|
|
223
257
|
end
|
|
224
258
|
end
|
|
225
259
|
|
|
260
|
+
module Errgonomic
|
|
261
|
+
module Option
|
|
262
|
+
# An Option is already lifted. Lifting it again would nest it, and the
|
|
263
|
+
# nesting is invisible until something reaches for the inner value.
|
|
264
|
+
class Any
|
|
265
|
+
def to_option
|
|
266
|
+
self
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
226
272
|
module Errgonomic
|
|
227
273
|
module Rails
|
|
228
274
|
# Teach ActiveRecord SQL quoting to unwrap Options, quoting a None as
|
data/lib/errgonomic/version.rb
CHANGED