activemodel 7.0.7.2 → 7.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +133 -187
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -9
- data/lib/active_model/access.rb +16 -0
- data/lib/active_model/api.rb +5 -5
- data/lib/active_model/attribute/user_provided_default.rb +4 -0
- data/lib/active_model/attribute.rb +26 -1
- data/lib/active_model/attribute_assignment.rb +1 -1
- data/lib/active_model/attribute_methods.rb +102 -63
- data/lib/active_model/attribute_registration.rb +77 -0
- data/lib/active_model/attribute_set.rb +9 -0
- data/lib/active_model/attributes.rb +62 -45
- data/lib/active_model/callbacks.rb +5 -5
- data/lib/active_model/conversion.rb +14 -4
- data/lib/active_model/deprecator.rb +7 -0
- data/lib/active_model/dirty.rb +134 -13
- data/lib/active_model/error.rb +4 -3
- data/lib/active_model/errors.rb +17 -12
- data/lib/active_model/forbidden_attributes_protection.rb +2 -0
- data/lib/active_model/gem_version.rb +4 -4
- data/lib/active_model/lint.rb +1 -1
- data/lib/active_model/locale/en.yml +4 -3
- data/lib/active_model/model.rb +26 -2
- data/lib/active_model/naming.rb +29 -10
- data/lib/active_model/railtie.rb +4 -0
- data/lib/active_model/secure_password.rb +61 -23
- data/lib/active_model/serialization.rb +3 -3
- data/lib/active_model/serializers/json.rb +1 -1
- data/lib/active_model/translation.rb +18 -16
- data/lib/active_model/type/big_integer.rb +23 -1
- data/lib/active_model/type/binary.rb +7 -1
- data/lib/active_model/type/boolean.rb +11 -9
- data/lib/active_model/type/date.rb +28 -2
- data/lib/active_model/type/date_time.rb +45 -3
- data/lib/active_model/type/decimal.rb +39 -1
- data/lib/active_model/type/float.rb +30 -1
- data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +5 -1
- data/lib/active_model/type/helpers/numeric.rb +4 -0
- data/lib/active_model/type/helpers/time_value.rb +28 -12
- data/lib/active_model/type/immutable_string.rb +37 -1
- data/lib/active_model/type/integer.rb +44 -1
- data/lib/active_model/type/serialize_cast_value.rb +47 -0
- data/lib/active_model/type/string.rb +9 -1
- data/lib/active_model/type/time.rb +48 -7
- data/lib/active_model/type/value.rb +17 -1
- data/lib/active_model/type.rb +1 -0
- data/lib/active_model/validations/absence.rb +1 -1
- data/lib/active_model/validations/acceptance.rb +1 -1
- data/lib/active_model/validations/callbacks.rb +4 -4
- data/lib/active_model/validations/clusivity.rb +5 -8
- data/lib/active_model/validations/comparability.rb +0 -11
- data/lib/active_model/validations/comparison.rb +15 -7
- data/lib/active_model/validations/confirmation.rb +1 -1
- data/lib/active_model/validations/format.rb +6 -7
- data/lib/active_model/validations/length.rb +10 -8
- data/lib/active_model/validations/numericality.rb +35 -23
- data/lib/active_model/validations/presence.rb +2 -2
- data/lib/active_model/validations/resolve_value.rb +26 -0
- data/lib/active_model/validations/validates.rb +4 -4
- data/lib/active_model/validations/with.rb +9 -2
- data/lib/active_model/validations.rb +45 -10
- data/lib/active_model/validator.rb +7 -5
- data/lib/active_model/version.rb +1 -1
- data/lib/active_model.rb +5 -1
- metadata +15 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7bead2532e6ee2356d90a899c3f4b72a130b214f5c98b7db0cc37fe1f2fffbb7
|
4
|
+
data.tar.gz: fb9bd5f3c104cf093adfe01097f5032a60605d8d933b32acf4f11575d0857172
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21ca777c14c33a0383e08ca5e3d62e478d7d62d104119675be305b5c1365624d3676bd6e21f6d9dee081cfc3d6c44c9e9e2b5dd362b6a3ecd108f3430c0b58ed
|
7
|
+
data.tar.gz: 1f251ea6da1c7d4cf7f0e6a404fd724d534488518e5c528eeaa6b31843655290ea181d6adcc47e6477863a19543af426bef904b2f6b3835826ad6d9545710876
|
data/CHANGELOG.md
CHANGED
@@ -1,14 +1,18 @@
|
|
1
|
-
## Rails 7.0.
|
1
|
+
## Rails 7.1.0.beta1 (September 13, 2023) ##
|
2
2
|
|
3
|
-
*
|
3
|
+
* Support composite identifiers in `to_key`
|
4
4
|
|
5
|
+
`to_key` avoids wrapping `#id` value into an `Array` if `#id` already an array
|
5
6
|
|
6
|
-
|
7
|
+
*Nikita Vasilevsky*
|
7
8
|
|
8
|
-
*
|
9
|
+
* Add `ActiveModel::Conversion.param_delimiter` to configure delimiter being used in `to_param`
|
9
10
|
|
11
|
+
*Nikita Vasilevsky*
|
10
12
|
|
11
|
-
|
13
|
+
* `undefine_attribute_methods` undefines alias attribute methods along with attribute methods.
|
14
|
+
|
15
|
+
*Nikita Vasilevsky*
|
12
16
|
|
13
17
|
* Error.full_message now strips ":base" from the message.
|
14
18
|
|
@@ -17,243 +21,185 @@
|
|
17
21
|
* Add a load hook for `ActiveModel::Model` (named `active_model`) to match the load hook for
|
18
22
|
`ActiveRecord::Base` and allow for overriding aspects of the `ActiveModel::Model` class.
|
19
23
|
|
24
|
+
*Lewis Buckley*
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
* No changes.
|
24
|
-
|
25
|
-
|
26
|
-
## Rails 7.0.5.1 (June 26, 2023) ##
|
27
|
-
|
28
|
-
* No changes.
|
29
|
-
|
30
|
-
|
31
|
-
## Rails 7.0.5 (May 24, 2023) ##
|
32
|
-
|
33
|
-
* No changes.
|
34
|
-
|
35
|
-
|
36
|
-
## Rails 7.0.4.3 (March 13, 2023) ##
|
37
|
-
|
38
|
-
* No changes.
|
39
|
-
|
40
|
-
|
41
|
-
## Rails 7.0.4.2 (January 24, 2023) ##
|
26
|
+
* Improve password length validation in ActiveModel::SecurePassword to consider byte size for BCrypt
|
27
|
+
compatibility.
|
42
28
|
|
43
|
-
|
29
|
+
The previous password length validation only considered the character count, which may not
|
30
|
+
accurately reflect the 72-byte size limit imposed by BCrypt. This change updates the validation
|
31
|
+
to consider both character count and byte size while keeping the character length validation in place.
|
44
32
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
33
|
+
```ruby
|
34
|
+
user = User.new(password: "a" * 73) # 73 characters
|
35
|
+
user.valid? # => false
|
36
|
+
user.errors[:password] # => ["is too long"]
|
49
37
|
|
50
38
|
|
51
|
-
|
39
|
+
user = User.new(password: "あ" * 25) # 25 characters, 75 bytes
|
40
|
+
user.valid? # => false
|
41
|
+
user.errors[:password] # => ["is too long"]
|
42
|
+
```
|
52
43
|
|
53
|
-
*
|
44
|
+
*ChatGPT*, *Guillermo Iguaran*
|
54
45
|
|
55
|
-
|
56
|
-
the
|
46
|
+
* `has_secure_password` now generates an `#{attribute}_salt` method that returns the salt
|
47
|
+
used to compute the password digest. The salt will change whenever the password is changed,
|
48
|
+
so it can be used to create single-use password reset tokens with `generates_token_for`:
|
57
49
|
|
58
50
|
```ruby
|
59
|
-
class
|
60
|
-
|
61
|
-
define_attribute_methods :x
|
62
|
-
end
|
51
|
+
class User < ActiveRecord::Base
|
52
|
+
has_secure_password
|
63
53
|
|
64
|
-
|
65
|
-
|
66
|
-
|
54
|
+
generates_token_for :password_reset, expires_in: 15.minutes do
|
55
|
+
password_salt&.last(10)
|
56
|
+
end
|
67
57
|
end
|
68
58
|
```
|
69
59
|
|
70
|
-
*
|
71
|
-
|
72
|
-
## Rails 7.0.3.1 (July 12, 2022) ##
|
73
|
-
|
74
|
-
* No changes.
|
75
|
-
|
76
|
-
|
77
|
-
## Rails 7.0.3 (May 09, 2022) ##
|
78
|
-
|
79
|
-
* No changes.
|
80
|
-
|
81
|
-
|
82
|
-
## Rails 7.0.2.4 (April 26, 2022) ##
|
83
|
-
|
84
|
-
* No changes.
|
85
|
-
|
86
|
-
|
87
|
-
## Rails 7.0.2.3 (March 08, 2022) ##
|
88
|
-
|
89
|
-
* No changes.
|
90
|
-
|
91
|
-
|
92
|
-
## Rails 7.0.2.2 (February 11, 2022) ##
|
93
|
-
|
94
|
-
* No changes.
|
95
|
-
|
96
|
-
|
97
|
-
## Rails 7.0.2.1 (February 11, 2022) ##
|
98
|
-
|
99
|
-
* No changes.
|
100
|
-
|
101
|
-
|
102
|
-
## Rails 7.0.2 (February 08, 2022) ##
|
103
|
-
|
104
|
-
* Use different cache namespace for proxy calls
|
105
|
-
|
106
|
-
Models can currently have different attribute bodies for the same method
|
107
|
-
names, leading to conflicts. Adding a new namespace `:active_model_proxy`
|
108
|
-
fixes the issue.
|
109
|
-
|
110
|
-
*Chris Salzberg*
|
111
|
-
|
112
|
-
|
113
|
-
## Rails 7.0.1 (January 06, 2022) ##
|
114
|
-
|
115
|
-
* No changes.
|
116
|
-
|
60
|
+
*Lázaro Nixon*
|
117
61
|
|
118
|
-
|
62
|
+
* Improve typography of user facing error messages. In English contractions,
|
63
|
+
the Unicode APOSTROPHE (`U+0027`) is now RIGHT SINGLE QUOTATION MARK
|
64
|
+
(`U+2019`). For example, "can't be blank" is now "can’t be blank".
|
119
65
|
|
120
|
-
*
|
66
|
+
*Jon Dufresne*
|
121
67
|
|
68
|
+
* Add class to `ActiveModel::MissingAttributeError` error message.
|
122
69
|
|
123
|
-
|
70
|
+
Show which class is missing the attribute in the error message:
|
124
71
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
* No changes.
|
131
|
-
|
132
|
-
## Rails 7.0.0.rc1 (December 06, 2021) ##
|
133
|
-
|
134
|
-
* Remove support to Marshal load Rails 5.x `ActiveModel::AttributeSet` format.
|
135
|
-
|
136
|
-
*Rafael Mendonça França*
|
137
|
-
|
138
|
-
* Remove support to Marshal and YAML load Rails 5.x error format.
|
139
|
-
|
140
|
-
*Rafael Mendonça França*
|
141
|
-
|
142
|
-
* Remove deprecated support to use `[]=` in `ActiveModel::Errors#messages`.
|
143
|
-
|
144
|
-
*Rafael Mendonça França*
|
145
|
-
|
146
|
-
* Remove deprecated support to `delete` errors from `ActiveModel::Errors#messages`.
|
147
|
-
|
148
|
-
*Rafael Mendonça França*
|
149
|
-
|
150
|
-
* Remove deprecated support to `clear` errors from `ActiveModel::Errors#messages`.
|
151
|
-
|
152
|
-
*Rafael Mendonça França*
|
72
|
+
```ruby
|
73
|
+
user = User.first
|
74
|
+
user.pets.select(:id).first.user_id
|
75
|
+
# => ActiveModel::MissingAttributeError: missing attribute 'user_id' for Pet
|
76
|
+
```
|
153
77
|
|
154
|
-
*
|
78
|
+
*Petrik de Heus*
|
155
79
|
|
156
|
-
|
80
|
+
* Raise `NoMethodError` in `ActiveModel::Type::Value#as_json` to avoid unpredictable
|
81
|
+
results.
|
157
82
|
|
158
|
-
*
|
83
|
+
*Vasiliy Ermolovich*
|
159
84
|
|
160
|
-
|
85
|
+
* Custom attribute types that inherit from Active Model built-in types and do
|
86
|
+
not override the `serialize` method will now benefit from an optimization
|
87
|
+
when serializing attribute values for the database.
|
161
88
|
|
162
|
-
|
89
|
+
For example, with a custom type like the following:
|
163
90
|
|
164
|
-
|
91
|
+
```ruby
|
92
|
+
class DowncasedString < ActiveModel::Type::String
|
93
|
+
def cast(value)
|
94
|
+
super&.downcase
|
95
|
+
end
|
96
|
+
end
|
165
97
|
|
166
|
-
|
98
|
+
ActiveRecord::Type.register(:downcased_string, DowncasedString)
|
167
99
|
|
168
|
-
|
100
|
+
class User < ActiveRecord::Base
|
101
|
+
attribute :email, :downcased_string
|
102
|
+
end
|
169
103
|
|
170
|
-
|
104
|
+
user = User.new(email: "FooBar@example.com")
|
105
|
+
```
|
171
106
|
|
172
|
-
|
107
|
+
Serializing the `email` attribute for the database will be roughly twice as
|
108
|
+
fast. More expensive `cast` operations will likely see greater improvements.
|
173
109
|
|
174
|
-
*
|
110
|
+
*Jonathan Hefner*
|
175
111
|
|
176
|
-
|
112
|
+
* `has_secure_password` now supports password challenges via a
|
113
|
+
`password_challenge` accessor and validation.
|
177
114
|
|
178
|
-
|
115
|
+
A password challenge is a safeguard to verify that the current user is
|
116
|
+
actually the password owner. It can be used when changing sensitive model
|
117
|
+
fields, such as the password itself. It is different than a password
|
118
|
+
confirmation, which is used to prevent password typos.
|
179
119
|
|
180
|
-
|
120
|
+
When `password_challenge` is set, the validation checks that the value's
|
121
|
+
digest matches the *currently persisted* `password_digest` (i.e.
|
122
|
+
`password_digest_was`).
|
181
123
|
|
182
|
-
|
124
|
+
This allows a password challenge to be done as part of a typical `update`
|
125
|
+
call, just like a password confirmation. It also allows a password
|
126
|
+
challenge error to be handled in the same way as other validation errors.
|
183
127
|
|
184
|
-
|
128
|
+
For example, in the controller, instead of:
|
185
129
|
|
186
|
-
|
187
|
-
|
130
|
+
```ruby
|
131
|
+
password_params = params.require(:password).permit(
|
132
|
+
:password_challenge,
|
133
|
+
:password,
|
134
|
+
:password_confirmation,
|
135
|
+
)
|
188
136
|
|
189
|
-
|
137
|
+
password_challenge = password_params.delete(:password_challenge)
|
138
|
+
@password_challenge_failed = !current_user.authenticate(password_challenge)
|
190
139
|
|
191
|
-
|
140
|
+
if !@password_challenge_failed && current_user.update(password_params)
|
141
|
+
# ...
|
142
|
+
end
|
143
|
+
```
|
192
144
|
|
193
|
-
|
194
|
-
user.password = nil
|
145
|
+
You can now write:
|
195
146
|
|
196
|
-
|
147
|
+
```ruby
|
148
|
+
password_params = params.require(:password).permit(
|
149
|
+
:password_challenge,
|
150
|
+
:password,
|
151
|
+
:password_confirmation,
|
152
|
+
).with_defaults(password_challenge: "")
|
153
|
+
|
154
|
+
if current_user.update(password_params)
|
155
|
+
# ...
|
156
|
+
end
|
157
|
+
```
|
197
158
|
|
198
|
-
|
159
|
+
And, in the view, instead of checking `@password_challenge_failed`, you can
|
160
|
+
render an error for the `password_challenge` field just as you would for
|
161
|
+
other form fields, including utilizing `config.action_view.field_error_proc`.
|
199
162
|
|
200
|
-
|
163
|
+
*Jonathan Hefner*
|
201
164
|
|
202
|
-
*
|
165
|
+
* Support infinite ranges for `LengthValidator`s `:in`/`:within` options
|
203
166
|
|
167
|
+
```ruby
|
168
|
+
validates_length_of :first_name, in: ..30
|
169
|
+
```
|
204
170
|
|
205
|
-
|
171
|
+
*fatkodima*
|
206
172
|
|
207
|
-
*
|
173
|
+
* Add support for beginless ranges to inclusivity/exclusivity validators:
|
208
174
|
|
209
|
-
|
210
|
-
|
175
|
+
```ruby
|
176
|
+
validates_inclusion_of :birth_date, in: -> { (..Date.today) }
|
177
|
+
```
|
211
178
|
|
212
|
-
*
|
179
|
+
*Bo Jeanes*
|
213
180
|
|
214
|
-
*
|
181
|
+
* Make validators accept lambdas without record argument
|
215
182
|
|
216
|
-
|
217
|
-
|
183
|
+
```ruby
|
184
|
+
# Before
|
185
|
+
validates_comparison_of :birth_date, less_than_or_equal_to: ->(_record) { Date.today }
|
218
186
|
|
219
|
-
|
187
|
+
# After
|
188
|
+
validates_comparison_of :birth_date, less_than_or_equal_to: -> { Date.today }
|
189
|
+
```
|
220
190
|
|
221
|
-
*
|
191
|
+
*fatkodima*
|
222
192
|
|
223
|
-
|
193
|
+
* Fix casting long strings to `Date`, `Time` or `DateTime`
|
224
194
|
|
225
|
-
*
|
195
|
+
*fatkodima*
|
226
196
|
|
227
|
-
*
|
197
|
+
* Use different cache namespace for proxy calls
|
228
198
|
|
229
|
-
|
199
|
+
Models can currently have different attribute bodies for the same method
|
200
|
+
names, leading to conflicts. Adding a new namespace `:active_model_proxy`
|
201
|
+
fixes the issue.
|
230
202
|
|
231
203
|
*Chris Salzberg*
|
232
204
|
|
233
|
-
|
234
|
-
|
235
|
-
Passing a last positional argument `{}` would be incorrectly considered as keyword argument.
|
236
|
-
|
237
|
-
*Benoit Daloze*
|
238
|
-
|
239
|
-
* Cache and re-use generated attribute methods.
|
240
|
-
|
241
|
-
Generated methods with identical implementations will now share their instruction sequences
|
242
|
-
leading to reduced memory retention, and slightly faster load time.
|
243
|
-
|
244
|
-
*Jean Boussier*
|
245
|
-
|
246
|
-
* Add `in: range` parameter to `numericality` validator.
|
247
|
-
|
248
|
-
*Michal Papis*
|
249
|
-
|
250
|
-
* Add `locale` argument to `ActiveModel::Name#initialize` to be used to generate the `singular`,
|
251
|
-
`plural`, `route_key` and `singular_route_key` values.
|
252
|
-
|
253
|
-
*Lukas Pokorny*
|
254
|
-
|
255
|
-
* Make ActiveModel::Errors#inspect slimmer for readability
|
256
|
-
|
257
|
-
*lulalala*
|
258
|
-
|
259
|
-
Please check [6-1-stable](https://github.com/rails/rails/blob/6-1-stable/activemodel/CHANGELOG.md) for previous changes.
|
205
|
+
Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/activemodel/CHANGELOG.md) for previous changes.
|
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
= Active Model -- model interfaces for Rails
|
1
|
+
= Active Model -- model interfaces for \Rails
|
2
2
|
|
3
3
|
Active Model provides a known set of interfaces for usage in model classes.
|
4
4
|
They allow for Action Pack helpers to interact with non-Active Record models,
|
5
5
|
for example. Active Model also helps with building custom ORMs for use outside of
|
6
|
-
the Rails framework.
|
6
|
+
the \Rails framework.
|
7
7
|
|
8
|
-
You can read more about Active Model in the {Active Model Basics}[https://
|
8
|
+
You can read more about Active Model in the {Active Model Basics}[https://guides.rubyonrails.org/active_model_basics.html] guide.
|
9
9
|
|
10
|
-
Prior to Rails 3.0, if a plugin or gem developer wanted to have an object
|
10
|
+
Prior to \Rails 3.0, if a plugin or gem developer wanted to have an object
|
11
11
|
interact with Action Pack helpers, it was required to either copy chunks of
|
12
|
-
code from Rails, or monkey patch entire helpers to make them handle objects
|
12
|
+
code from \Rails, or monkey patch entire helpers to make them handle objects
|
13
13
|
that did not exactly conform to the Active Record interface. This would result
|
14
14
|
in code duplication and fragile applications that broke on upgrades. Active
|
15
15
|
Model solves this by defining an explicit API. You can read more about the
|
16
|
-
API in
|
16
|
+
API in +ActiveModel::Lint::Tests+.
|
17
17
|
|
18
18
|
Active Model provides a default module that implements the basic API required
|
19
|
-
to integrate with Action Pack out of the box:
|
19
|
+
to integrate with Action Pack out of the box: ActiveModel::API.
|
20
20
|
|
21
21
|
class Person
|
22
22
|
include ActiveModel::API
|
@@ -32,7 +32,7 @@ to integrate with Action Pack out of the box: <tt>ActiveModel::API</tt>.
|
|
32
32
|
|
33
33
|
It includes model name introspections, conversions, translations and
|
34
34
|
validations, resulting in a class suitable to be used with Action Pack.
|
35
|
-
See
|
35
|
+
See ActiveModel::API for more examples.
|
36
36
|
|
37
37
|
Active Model also provides the following functionality to have ORM-like
|
38
38
|
behavior out of the box:
|
@@ -156,7 +156,7 @@ behavior out of the box:
|
|
156
156
|
|
157
157
|
* Making objects serializable
|
158
158
|
|
159
|
-
|
159
|
+
ActiveModel::Serialization provides a standard interface for your object
|
160
160
|
to provide +to_json+ serialization.
|
161
161
|
|
162
162
|
class SerialPerson
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
require "active_support/core_ext/hash/indifferent_access"
|
5
|
+
|
6
|
+
module ActiveModel
|
7
|
+
module Access # :nodoc:
|
8
|
+
def slice(*methods)
|
9
|
+
methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
|
10
|
+
end
|
11
|
+
|
12
|
+
def values_at(*methods)
|
13
|
+
methods.flatten.map! { |method| public_send(method) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/active_model/api.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveModel
|
4
|
-
#
|
4
|
+
# = Active \Model \API
|
5
5
|
#
|
6
6
|
# Includes the required interface for an object to interact with
|
7
|
-
# Action Pack and Action View, using different Active Model modules.
|
7
|
+
# Action Pack and Action View, using different Active \Model modules.
|
8
8
|
# It includes model name introspections, conversions, translations, and
|
9
9
|
# validations. Besides that, it allows you to initialize the object with a
|
10
10
|
# hash of attributes, pretty much like Active Record does.
|
@@ -20,7 +20,7 @@ module ActiveModel
|
|
20
20
|
# person.name # => "bob"
|
21
21
|
# person.age # => "18"
|
22
22
|
#
|
23
|
-
# Note that, by default,
|
23
|
+
# Note that, by default, +ActiveModel::API+ implements #persisted?
|
24
24
|
# to return +false+, which is the most common case. You may want to override
|
25
25
|
# it in your class to simulate a different scenario:
|
26
26
|
#
|
@@ -36,7 +36,7 @@ module ActiveModel
|
|
36
36
|
# person = Person.new(id: 1, name: 'bob')
|
37
37
|
# person.persisted? # => true
|
38
38
|
#
|
39
|
-
# Also, if for some reason you need to run code on
|
39
|
+
# Also, if for some reason you need to run code on initialize ( ::new ), make
|
40
40
|
# sure you call +super+ if you want the attributes hash initialization to
|
41
41
|
# happen.
|
42
42
|
#
|
@@ -54,7 +54,7 @@ module ActiveModel
|
|
54
54
|
# person.omg # => true
|
55
55
|
#
|
56
56
|
# For more detailed information on other functionalities available, please
|
57
|
-
# refer to the specific modules included in
|
57
|
+
# refer to the specific modules included in +ActiveModel::API+
|
58
58
|
# (see below).
|
59
59
|
module API
|
60
60
|
extend ActiveSupport::Concern
|
@@ -4,6 +4,10 @@ require "active_model/attribute"
|
|
4
4
|
|
5
5
|
module ActiveModel
|
6
6
|
class Attribute # :nodoc:
|
7
|
+
def with_user_default(value)
|
8
|
+
UserProvidedDefault.new(name, value, type, self.is_a?(FromDatabase) ? self : original_attribute)
|
9
|
+
end
|
10
|
+
|
7
11
|
class UserProvidedDefault < FromUser # :nodoc:
|
8
12
|
def initialize(name, value, type, database_default)
|
9
13
|
@user_provided_value = value
|
@@ -53,7 +53,10 @@ module ActiveModel
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def value_for_database
|
56
|
-
type.
|
56
|
+
if !defined?(@value_for_database) || type.changed_in_place?(@value_for_database, value)
|
57
|
+
@value_for_database = _value_for_database
|
58
|
+
end
|
59
|
+
@value_for_database
|
57
60
|
end
|
58
61
|
|
59
62
|
def serializable?(&block)
|
@@ -159,6 +162,10 @@ module ActiveModel
|
|
159
162
|
assigned? && type.changed?(original_value, value, value_before_type_cast)
|
160
163
|
end
|
161
164
|
|
165
|
+
def _value_for_database
|
166
|
+
type.serialize(value)
|
167
|
+
end
|
168
|
+
|
162
169
|
def _original_value_for_database
|
163
170
|
type.serialize(original_value)
|
164
171
|
end
|
@@ -168,6 +175,19 @@ module ActiveModel
|
|
168
175
|
type.deserialize(value)
|
169
176
|
end
|
170
177
|
|
178
|
+
def forgetting_assignment
|
179
|
+
# If this attribute was not persisted (with a `value_for_database`
|
180
|
+
# that might differ from `value_before_type_cast`) and `value` has not
|
181
|
+
# changed in place, we can simply dup this attribute to avoid
|
182
|
+
# deserialize / cast / serialize calls from computing the new
|
183
|
+
# attribute's `value_before_type_cast`.
|
184
|
+
if !defined?(@value_for_database) && !changed_in_place?
|
185
|
+
dup
|
186
|
+
else
|
187
|
+
super
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
171
191
|
private
|
172
192
|
def _original_value_for_database
|
173
193
|
value_before_type_cast
|
@@ -182,6 +202,11 @@ module ActiveModel
|
|
182
202
|
def came_from_user?
|
183
203
|
!type.value_constructed_by_mass_assignment?(value_before_type_cast)
|
184
204
|
end
|
205
|
+
|
206
|
+
private
|
207
|
+
def _value_for_database
|
208
|
+
Type::SerializeCastValue.serialize(type, value)
|
209
|
+
end
|
185
210
|
end
|
186
211
|
|
187
212
|
class WithCastValue < Attribute # :nodoc:
|
@@ -10,7 +10,7 @@ module ActiveModel
|
|
10
10
|
# keys matching the attribute names.
|
11
11
|
#
|
12
12
|
# If the passed hash responds to <tt>permitted?</tt> method and the return value
|
13
|
-
# of this method is +false+ an
|
13
|
+
# of this method is +false+ an ActiveModel::ForbiddenAttributesError
|
14
14
|
# exception is raised.
|
15
15
|
#
|
16
16
|
# class Cat
|