activemodel 7.0.5 → 7.1.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +158 -123
- data/MIT-LICENSE +1 -1
- data/README.rdoc +11 -11
- 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 +103 -64
- data/lib/active_model/attribute_registration.rb +77 -0
- data/lib/active_model/attribute_set.rb +10 -1
- 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 +5 -4
- data/lib/active_model/errors.rb +37 -6
- 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 +1 -0
- data/lib/active_model/model.rb +34 -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 +10 -2
- 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/mutable.rb +4 -4
- data/lib/active_model/type/helpers/numeric.rb +6 -1
- 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 +23 -3
- 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/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 +1 -1
- 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 +44 -9
- data/lib/active_model/validator.rb +7 -5
- data/lib/active_model/version.rb +1 -1
- data/lib/active_model.rb +5 -1
- metadata +16 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 62a8e27551c3779ec7676e6d2e0e66c13c2a8f95c88562722bfdcb8d9d319f2f
|
4
|
+
data.tar.gz: 2cd6f1f9bcf63a13c2688fbc6854d1173f657bfecbfca5ef9a24bd06b5c61f32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e2132e134510005376a33192f81e408fdc3e5813f368c7c8a0ce2b00328d963c94970549219a7e9b2352136a8c223da5bb2e753e9cae9e43ce2b0f6304ad8df
|
7
|
+
data.tar.gz: bb81aaefa19e40042623a008d8e4d0e062f35590f4150eabb6349dd0b394b3b0d58276b2acdf17137a09c4f25a97caf011069590ff09cebb43581a3d7549919b
|
data/CHANGELOG.md
CHANGED
@@ -1,229 +1,264 @@
|
|
1
|
-
## Rails 7.
|
1
|
+
## Rails 7.1.3.4 (June 04, 2024) ##
|
2
2
|
|
3
3
|
* No changes.
|
4
4
|
|
5
5
|
|
6
|
-
## Rails 7.
|
6
|
+
## Rails 7.1.3.3 (May 16, 2024) ##
|
7
7
|
|
8
8
|
* No changes.
|
9
9
|
|
10
10
|
|
11
|
-
## Rails 7.
|
11
|
+
## Rails 7.1.3.2 (February 21, 2024) ##
|
12
12
|
|
13
13
|
* No changes.
|
14
14
|
|
15
15
|
|
16
|
-
## Rails 7.
|
16
|
+
## Rails 7.1.3.1 (February 21, 2024) ##
|
17
17
|
|
18
18
|
* No changes.
|
19
19
|
|
20
20
|
|
21
|
-
## Rails 7.
|
22
|
-
|
23
|
-
* Handle name clashes in attribute methods code generation cache.
|
24
|
-
|
25
|
-
When two distinct attribute methods would generate similar names,
|
26
|
-
the first implementation would be incorrectly re-used.
|
27
|
-
|
28
|
-
```ruby
|
29
|
-
class A
|
30
|
-
attribute_method_suffix "_changed?"
|
31
|
-
define_attribute_methods :x
|
32
|
-
end
|
33
|
-
|
34
|
-
class B
|
35
|
-
attribute_method_suffix "?"
|
36
|
-
define_attribute_methods :x_changed
|
37
|
-
end
|
38
|
-
```
|
39
|
-
|
40
|
-
*Jean Boussier*
|
41
|
-
|
42
|
-
## Rails 7.0.3.1 (July 12, 2022) ##
|
21
|
+
## Rails 7.1.3 (January 16, 2024) ##
|
43
22
|
|
44
23
|
* No changes.
|
45
24
|
|
46
25
|
|
47
|
-
## Rails 7.
|
48
|
-
|
49
|
-
* No changes.
|
26
|
+
## Rails 7.1.2 (November 10, 2023) ##
|
50
27
|
|
28
|
+
* Make `==(other)` method of AttributeSet safe.
|
51
29
|
|
52
|
-
|
30
|
+
*Dmitry Pogrebnoy*
|
53
31
|
|
54
|
-
* No changes.
|
55
32
|
|
56
|
-
|
57
|
-
## Rails 7.0.2.3 (March 08, 2022) ##
|
33
|
+
## Rails 7.1.1 (October 11, 2023) ##
|
58
34
|
|
59
35
|
* No changes.
|
60
36
|
|
61
37
|
|
62
|
-
## Rails 7.0
|
38
|
+
## Rails 7.1.0 (October 05, 2023) ##
|
63
39
|
|
64
40
|
* No changes.
|
65
41
|
|
66
42
|
|
67
|
-
## Rails 7.0.
|
43
|
+
## Rails 7.1.0.rc2 (October 01, 2023) ##
|
68
44
|
|
69
45
|
* No changes.
|
70
46
|
|
71
47
|
|
72
|
-
## Rails 7.0.
|
73
|
-
|
74
|
-
* Use different cache namespace for proxy calls
|
75
|
-
|
76
|
-
Models can currently have different attribute bodies for the same method
|
77
|
-
names, leading to conflicts. Adding a new namespace `:active_model_proxy`
|
78
|
-
fixes the issue.
|
79
|
-
|
80
|
-
*Chris Salzberg*
|
81
|
-
|
48
|
+
## Rails 7.1.0.rc1 (September 27, 2023) ##
|
82
49
|
|
83
|
-
|
50
|
+
* Remove change in the typography of user facing error messages.
|
51
|
+
For example, “can’t be blank” is again “can't be blank”.
|
84
52
|
|
85
|
-
*
|
53
|
+
*Rafael Mendonça França*
|
86
54
|
|
87
55
|
|
88
|
-
## Rails 7.0.
|
56
|
+
## Rails 7.1.0.beta1 (September 13, 2023) ##
|
89
57
|
|
90
|
-
*
|
58
|
+
* Support composite identifiers in `to_key`
|
91
59
|
|
60
|
+
`to_key` avoids wrapping `#id` value into an `Array` if `#id` already an array
|
92
61
|
|
93
|
-
|
62
|
+
*Nikita Vasilevsky*
|
94
63
|
|
95
|
-
*
|
64
|
+
* Add `ActiveModel::Conversion.param_delimiter` to configure delimiter being used in `to_param`
|
96
65
|
|
66
|
+
*Nikita Vasilevsky*
|
97
67
|
|
98
|
-
|
68
|
+
* `undefine_attribute_methods` undefines alias attribute methods along with attribute methods.
|
99
69
|
|
100
|
-
*
|
70
|
+
*Nikita Vasilevsky*
|
101
71
|
|
102
|
-
|
72
|
+
* Error.full_message now strips ":base" from the message.
|
103
73
|
|
104
|
-
*
|
74
|
+
*zzak*
|
105
75
|
|
106
|
-
|
76
|
+
* Add a load hook for `ActiveModel::Model` (named `active_model`) to match the load hook for
|
77
|
+
`ActiveRecord::Base` and allow for overriding aspects of the `ActiveModel::Model` class.
|
107
78
|
|
108
|
-
*
|
79
|
+
*Lewis Buckley*
|
109
80
|
|
110
|
-
|
111
|
-
|
112
|
-
* Remove deprecated support to use `[]=` in `ActiveModel::Errors#messages`.
|
81
|
+
* Improve password length validation in ActiveModel::SecurePassword to consider byte size for BCrypt
|
82
|
+
compatibility.
|
113
83
|
|
114
|
-
|
84
|
+
The previous password length validation only considered the character count, which may not
|
85
|
+
accurately reflect the 72-byte size limit imposed by BCrypt. This change updates the validation
|
86
|
+
to consider both character count and byte size while keeping the character length validation in place.
|
115
87
|
|
116
|
-
|
117
|
-
|
118
|
-
|
88
|
+
```ruby
|
89
|
+
user = User.new(password: "a" * 73) # 73 characters
|
90
|
+
user.valid? # => false
|
91
|
+
user.errors[:password] # => ["is too long"]
|
119
92
|
|
120
|
-
* Remove deprecated support to `clear` errors from `ActiveModel::Errors#messages`.
|
121
93
|
|
122
|
-
*
|
94
|
+
user = User.new(password: "あ" * 25) # 25 characters, 75 bytes
|
95
|
+
user.valid? # => false
|
96
|
+
user.errors[:password] # => ["is too long"]
|
97
|
+
```
|
123
98
|
|
124
|
-
*
|
99
|
+
*ChatGPT*, *Guillermo Iguaran*
|
125
100
|
|
126
|
-
|
101
|
+
* `has_secure_password` now generates an `#{attribute}_salt` method that returns the salt
|
102
|
+
used to compute the password digest. The salt will change whenever the password is changed,
|
103
|
+
so it can be used to create single-use password reset tokens with `generates_token_for`:
|
127
104
|
|
128
|
-
|
105
|
+
```ruby
|
106
|
+
class User < ActiveRecord::Base
|
107
|
+
has_secure_password
|
129
108
|
|
130
|
-
|
109
|
+
generates_token_for :password_reset, expires_in: 15.minutes do
|
110
|
+
password_salt&.last(10)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
```
|
131
114
|
|
132
|
-
*
|
115
|
+
*Lázaro Nixon*
|
133
116
|
|
134
|
-
|
117
|
+
* Improve typography of user facing error messages. In English contractions,
|
118
|
+
the Unicode APOSTROPHE (`U+0027`) is now RIGHT SINGLE QUOTATION MARK
|
119
|
+
(`U+2019`). For example, "can't be blank" is now "can’t be blank".
|
135
120
|
|
136
|
-
*
|
121
|
+
*Jon Dufresne*
|
137
122
|
|
138
|
-
|
123
|
+
* Add class to `ActiveModel::MissingAttributeError` error message.
|
139
124
|
|
140
|
-
|
125
|
+
Show which class is missing the attribute in the error message:
|
141
126
|
|
142
|
-
|
127
|
+
```ruby
|
128
|
+
user = User.first
|
129
|
+
user.pets.select(:id).first.user_id
|
130
|
+
# => ActiveModel::MissingAttributeError: missing attribute 'user_id' for Pet
|
131
|
+
```
|
143
132
|
|
144
|
-
*
|
133
|
+
*Petrik de Heus*
|
145
134
|
|
146
|
-
|
135
|
+
* Raise `NoMethodError` in `ActiveModel::Type::Value#as_json` to avoid unpredictable
|
136
|
+
results.
|
147
137
|
|
148
|
-
*
|
138
|
+
*Vasiliy Ermolovich*
|
149
139
|
|
150
|
-
|
151
|
-
|
152
|
-
|
140
|
+
* Custom attribute types that inherit from Active Model built-in types and do
|
141
|
+
not override the `serialize` method will now benefit from an optimization
|
142
|
+
when serializing attribute values for the database.
|
153
143
|
|
154
|
-
|
144
|
+
For example, with a custom type like the following:
|
155
145
|
|
156
|
-
|
157
|
-
|
146
|
+
```ruby
|
147
|
+
class DowncasedString < ActiveModel::Type::String
|
148
|
+
def cast(value)
|
149
|
+
super&.downcase
|
150
|
+
end
|
151
|
+
end
|
158
152
|
|
159
|
-
|
153
|
+
ActiveRecord::Type.register(:downcased_string, DowncasedString)
|
160
154
|
|
161
|
-
|
155
|
+
class User < ActiveRecord::Base
|
156
|
+
attribute :email, :downcased_string
|
157
|
+
end
|
162
158
|
|
163
|
-
|
164
|
-
|
159
|
+
user = User.new(email: "FooBar@example.com")
|
160
|
+
```
|
165
161
|
|
166
|
-
|
162
|
+
Serializing the `email` attribute for the database will be roughly twice as
|
163
|
+
fast. More expensive `cast` operations will likely see greater improvements.
|
167
164
|
|
168
|
-
*
|
165
|
+
*Jonathan Hefner*
|
169
166
|
|
170
|
-
|
167
|
+
* `has_secure_password` now supports password challenges via a
|
168
|
+
`password_challenge` accessor and validation.
|
171
169
|
|
172
|
-
|
170
|
+
A password challenge is a safeguard to verify that the current user is
|
171
|
+
actually the password owner. It can be used when changing sensitive model
|
172
|
+
fields, such as the password itself. It is different than a password
|
173
|
+
confirmation, which is used to prevent password typos.
|
173
174
|
|
175
|
+
When `password_challenge` is set, the validation checks that the value's
|
176
|
+
digest matches the *currently persisted* `password_digest` (i.e.
|
177
|
+
`password_digest_was`).
|
174
178
|
|
175
|
-
|
179
|
+
This allows a password challenge to be done as part of a typical `update`
|
180
|
+
call, just like a password confirmation. It also allows a password
|
181
|
+
challenge error to be handled in the same way as other validation errors.
|
176
182
|
|
177
|
-
|
183
|
+
For example, in the controller, instead of:
|
178
184
|
|
179
|
-
|
180
|
-
|
185
|
+
```ruby
|
186
|
+
password_params = params.require(:password).permit(
|
187
|
+
:password_challenge,
|
188
|
+
:password,
|
189
|
+
:password_confirmation,
|
190
|
+
)
|
181
191
|
|
182
|
-
|
192
|
+
password_challenge = password_params.delete(:password_challenge)
|
193
|
+
@password_challenge_failed = !current_user.authenticate(password_challenge)
|
183
194
|
|
184
|
-
|
195
|
+
if !@password_challenge_failed && current_user.update(password_params)
|
196
|
+
# ...
|
197
|
+
end
|
198
|
+
```
|
185
199
|
|
186
|
-
|
187
|
-
and can't be compared with `==`.
|
200
|
+
You can now write:
|
188
201
|
|
189
|
-
|
202
|
+
```ruby
|
203
|
+
password_params = params.require(:password).permit(
|
204
|
+
:password_challenge,
|
205
|
+
:password,
|
206
|
+
:password_confirmation,
|
207
|
+
).with_defaults(password_challenge: "")
|
208
|
+
|
209
|
+
if current_user.update(password_params)
|
210
|
+
# ...
|
211
|
+
end
|
212
|
+
```
|
190
213
|
|
191
|
-
|
214
|
+
And, in the view, instead of checking `@password_challenge_failed`, you can
|
215
|
+
render an error for the `password_challenge` field just as you would for
|
216
|
+
other form fields, including utilizing `config.action_view.field_error_proc`.
|
192
217
|
|
193
|
-
|
218
|
+
*Jonathan Hefner*
|
194
219
|
|
195
|
-
|
220
|
+
* Support infinite ranges for `LengthValidator`s `:in`/`:within` options
|
196
221
|
|
197
|
-
|
222
|
+
```ruby
|
223
|
+
validates_length_of :first_name, in: ..30
|
224
|
+
```
|
198
225
|
|
199
|
-
|
226
|
+
*fatkodima*
|
200
227
|
|
201
|
-
|
228
|
+
* Add support for beginless ranges to inclusivity/exclusivity validators:
|
202
229
|
|
203
|
-
|
230
|
+
```ruby
|
231
|
+
validates_inclusion_of :birth_date, in: -> { (..Date.today) }
|
232
|
+
```
|
204
233
|
|
205
|
-
|
234
|
+
```ruby
|
235
|
+
validates_exclusion_of :birth_date, in: -> { (..Date.today) }
|
236
|
+
```
|
206
237
|
|
207
|
-
*
|
238
|
+
*Bo Jeanes*
|
208
239
|
|
209
|
-
*
|
240
|
+
* Make validators accept lambdas without record argument
|
210
241
|
|
211
|
-
|
212
|
-
|
242
|
+
```ruby
|
243
|
+
# Before
|
244
|
+
validates_comparison_of :birth_date, less_than_or_equal_to: ->(_record) { Date.today }
|
213
245
|
|
214
|
-
|
246
|
+
# After
|
247
|
+
validates_comparison_of :birth_date, less_than_or_equal_to: -> { Date.today }
|
248
|
+
```
|
215
249
|
|
216
|
-
*
|
250
|
+
*fatkodima*
|
217
251
|
|
218
|
-
|
252
|
+
* Fix casting long strings to `Date`, `Time` or `DateTime`
|
219
253
|
|
220
|
-
*
|
221
|
-
`plural`, `route_key` and `singular_route_key` values.
|
254
|
+
*fatkodima*
|
222
255
|
|
223
|
-
|
256
|
+
* Use different cache namespace for proxy calls
|
224
257
|
|
225
|
-
|
258
|
+
Models can currently have different attribute bodies for the same method
|
259
|
+
names, leading to conflicts. Adding a new namespace `:active_model_proxy`
|
260
|
+
fixes the issue.
|
226
261
|
|
227
|
-
*
|
262
|
+
*Chris Salzberg*
|
228
263
|
|
229
|
-
Please check [
|
264
|
+
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
|
@@ -239,7 +239,7 @@ The latest version of Active Model can be installed with RubyGems:
|
|
239
239
|
|
240
240
|
$ gem install activemodel
|
241
241
|
|
242
|
-
Source code can be downloaded as part of the Rails project on GitHub
|
242
|
+
Source code can be downloaded as part of the \Rails project on GitHub
|
243
243
|
|
244
244
|
* https://github.com/rails/rails/tree/main/activemodel
|
245
245
|
|
@@ -257,7 +257,7 @@ API documentation is at:
|
|
257
257
|
|
258
258
|
* https://api.rubyonrails.org
|
259
259
|
|
260
|
-
Bug reports for the Ruby on Rails project can be filed here:
|
260
|
+
Bug reports for the Ruby on \Rails project can be filed here:
|
261
261
|
|
262
262
|
* https://github.com/rails/rails/issues
|
263
263
|
|
@@ -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 use the existing `value_before_type_cast`
|
182
|
+
# to avoid 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
|
+
with_value_from_database(value_before_type_cast)
|
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
|