activemodel 7.0.4 → 7.1.3.4
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/CHANGELOG.md +162 -107
- 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 +133 -102
- data/lib/active_model/attribute_mutation_tracker.rb +10 -2
- 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 +6 -6
- 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 +13 -3
- 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 -0
- 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 +25 -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 +10 -12
- 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 +13 -12
- 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 +5 -5
- 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 +6 -1
- metadata +13 -8
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,209 +1,264 @@
|
|
|
1
|
-
## Rails 7.
|
|
1
|
+
## Rails 7.1.3.4 (June 04, 2024) ##
|
|
2
2
|
|
|
3
|
-
*
|
|
4
|
-
|
|
5
|
-
When two distinct attribute methods would generate similar names,
|
|
6
|
-
the first implementation would be incorrectly re-used.
|
|
7
|
-
|
|
8
|
-
```ruby
|
|
9
|
-
class A
|
|
10
|
-
attribute_method_suffix "_changed?"
|
|
11
|
-
define_attribute_methods :x
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
class B
|
|
15
|
-
attribute_method_suffix "?"
|
|
16
|
-
define_attribute_methods :x_changed
|
|
17
|
-
end
|
|
18
|
-
```
|
|
3
|
+
* No changes.
|
|
19
4
|
|
|
20
|
-
*Jean Boussier*
|
|
21
5
|
|
|
22
|
-
## Rails 7.
|
|
6
|
+
## Rails 7.1.3.3 (May 16, 2024) ##
|
|
23
7
|
|
|
24
8
|
* No changes.
|
|
25
9
|
|
|
26
10
|
|
|
27
|
-
## Rails 7.
|
|
11
|
+
## Rails 7.1.3.2 (February 21, 2024) ##
|
|
28
12
|
|
|
29
13
|
* No changes.
|
|
30
14
|
|
|
31
15
|
|
|
32
|
-
## Rails 7.
|
|
16
|
+
## Rails 7.1.3.1 (February 21, 2024) ##
|
|
33
17
|
|
|
34
18
|
* No changes.
|
|
35
19
|
|
|
36
20
|
|
|
37
|
-
## Rails 7.
|
|
21
|
+
## Rails 7.1.3 (January 16, 2024) ##
|
|
38
22
|
|
|
39
23
|
* No changes.
|
|
40
24
|
|
|
41
25
|
|
|
42
|
-
## Rails 7.
|
|
26
|
+
## Rails 7.1.2 (November 10, 2023) ##
|
|
43
27
|
|
|
44
|
-
*
|
|
28
|
+
* Make `==(other)` method of AttributeSet safe.
|
|
45
29
|
|
|
30
|
+
*Dmitry Pogrebnoy*
|
|
46
31
|
|
|
47
|
-
## Rails 7.0.2.1 (February 11, 2022) ##
|
|
48
|
-
|
|
49
|
-
* No changes.
|
|
50
32
|
|
|
33
|
+
## Rails 7.1.1 (October 11, 2023) ##
|
|
51
34
|
|
|
52
|
-
|
|
35
|
+
* No changes.
|
|
53
36
|
|
|
54
|
-
* Use different cache namespace for proxy calls
|
|
55
37
|
|
|
56
|
-
|
|
57
|
-
names, leading to conflicts. Adding a new namespace `:active_model_proxy`
|
|
58
|
-
fixes the issue.
|
|
38
|
+
## Rails 7.1.0 (October 05, 2023) ##
|
|
59
39
|
|
|
60
|
-
|
|
40
|
+
* No changes.
|
|
61
41
|
|
|
62
42
|
|
|
63
|
-
## Rails 7.0.
|
|
43
|
+
## Rails 7.1.0.rc2 (October 01, 2023) ##
|
|
64
44
|
|
|
65
45
|
* No changes.
|
|
66
46
|
|
|
67
47
|
|
|
68
|
-
## Rails 7.0.
|
|
48
|
+
## Rails 7.1.0.rc1 (September 27, 2023) ##
|
|
69
49
|
|
|
70
|
-
*
|
|
50
|
+
* Remove change in the typography of user facing error messages.
|
|
51
|
+
For example, “can’t be blank” is again “can't be blank”.
|
|
71
52
|
|
|
53
|
+
*Rafael Mendonça França*
|
|
72
54
|
|
|
73
|
-
## Rails 7.0.0.rc3 (December 14, 2021) ##
|
|
74
55
|
|
|
75
|
-
|
|
56
|
+
## Rails 7.1.0.beta1 (September 13, 2023) ##
|
|
76
57
|
|
|
58
|
+
* Support composite identifiers in `to_key`
|
|
77
59
|
|
|
78
|
-
|
|
60
|
+
`to_key` avoids wrapping `#id` value into an `Array` if `#id` already an array
|
|
79
61
|
|
|
80
|
-
*
|
|
62
|
+
*Nikita Vasilevsky*
|
|
81
63
|
|
|
82
|
-
|
|
64
|
+
* Add `ActiveModel::Conversion.param_delimiter` to configure delimiter being used in `to_param`
|
|
83
65
|
|
|
84
|
-
*
|
|
66
|
+
*Nikita Vasilevsky*
|
|
85
67
|
|
|
86
|
-
|
|
68
|
+
* `undefine_attribute_methods` undefines alias attribute methods along with attribute methods.
|
|
87
69
|
|
|
88
|
-
*
|
|
70
|
+
*Nikita Vasilevsky*
|
|
89
71
|
|
|
90
|
-
|
|
72
|
+
* Error.full_message now strips ":base" from the message.
|
|
91
73
|
|
|
92
|
-
*
|
|
74
|
+
*zzak*
|
|
93
75
|
|
|
94
|
-
|
|
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.
|
|
95
78
|
|
|
96
|
-
*
|
|
79
|
+
*Lewis Buckley*
|
|
97
80
|
|
|
98
|
-
|
|
81
|
+
* Improve password length validation in ActiveModel::SecurePassword to consider byte size for BCrypt
|
|
82
|
+
compatibility.
|
|
99
83
|
|
|
100
|
-
|
|
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.
|
|
101
87
|
|
|
102
|
-
|
|
88
|
+
```ruby
|
|
89
|
+
user = User.new(password: "a" * 73) # 73 characters
|
|
90
|
+
user.valid? # => false
|
|
91
|
+
user.errors[:password] # => ["is too long"]
|
|
103
92
|
|
|
104
|
-
* Remove deprecated support concat errors to `ActiveModel::Errors#messages`.
|
|
105
93
|
|
|
106
|
-
*
|
|
94
|
+
user = User.new(password: "あ" * 25) # 25 characters, 75 bytes
|
|
95
|
+
user.valid? # => false
|
|
96
|
+
user.errors[:password] # => ["is too long"]
|
|
97
|
+
```
|
|
107
98
|
|
|
108
|
-
*
|
|
99
|
+
*ChatGPT*, *Guillermo Iguaran*
|
|
109
100
|
|
|
110
|
-
|
|
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`:
|
|
111
104
|
|
|
112
|
-
|
|
105
|
+
```ruby
|
|
106
|
+
class User < ActiveRecord::Base
|
|
107
|
+
has_secure_password
|
|
113
108
|
|
|
114
|
-
|
|
109
|
+
generates_token_for :password_reset, expires_in: 15.minutes do
|
|
110
|
+
password_salt&.last(10)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
```
|
|
115
114
|
|
|
116
|
-
*
|
|
115
|
+
*Lázaro Nixon*
|
|
117
116
|
|
|
118
|
-
|
|
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".
|
|
119
120
|
|
|
120
|
-
*
|
|
121
|
+
*Jon Dufresne*
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
* Add class to `ActiveModel::MissingAttributeError` error message.
|
|
123
124
|
|
|
124
|
-
|
|
125
|
+
Show which class is missing the attribute in the error message:
|
|
125
126
|
|
|
126
|
-
|
|
127
|
+
```ruby
|
|
128
|
+
user = User.first
|
|
129
|
+
user.pets.select(:id).first.user_id
|
|
130
|
+
# => ActiveModel::MissingAttributeError: missing attribute 'user_id' for Pet
|
|
131
|
+
```
|
|
127
132
|
|
|
128
|
-
*
|
|
133
|
+
*Petrik de Heus*
|
|
129
134
|
|
|
130
|
-
|
|
135
|
+
* Raise `NoMethodError` in `ActiveModel::Type::Value#as_json` to avoid unpredictable
|
|
136
|
+
results.
|
|
131
137
|
|
|
132
|
-
*
|
|
138
|
+
*Vasiliy Ermolovich*
|
|
133
139
|
|
|
134
|
-
|
|
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.
|
|
135
143
|
|
|
136
|
-
|
|
137
|
-
user.password = nil
|
|
144
|
+
For example, with a custom type like the following:
|
|
138
145
|
|
|
139
|
-
|
|
146
|
+
```ruby
|
|
147
|
+
class DowncasedString < ActiveModel::Type::String
|
|
148
|
+
def cast(value)
|
|
149
|
+
super&.downcase
|
|
150
|
+
end
|
|
151
|
+
end
|
|
140
152
|
|
|
141
|
-
|
|
153
|
+
ActiveRecord::Type.register(:downcased_string, DowncasedString)
|
|
142
154
|
|
|
143
|
-
|
|
144
|
-
|
|
155
|
+
class User < ActiveRecord::Base
|
|
156
|
+
attribute :email, :downcased_string
|
|
157
|
+
end
|
|
145
158
|
|
|
146
|
-
|
|
159
|
+
user = User.new(email: "FooBar@example.com")
|
|
160
|
+
```
|
|
147
161
|
|
|
148
|
-
|
|
162
|
+
Serializing the `email` attribute for the database will be roughly twice as
|
|
163
|
+
fast. More expensive `cast` operations will likely see greater improvements.
|
|
149
164
|
|
|
150
|
-
|
|
165
|
+
*Jonathan Hefner*
|
|
151
166
|
|
|
152
|
-
*
|
|
167
|
+
* `has_secure_password` now supports password challenges via a
|
|
168
|
+
`password_challenge` accessor and validation.
|
|
153
169
|
|
|
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.
|
|
154
174
|
|
|
155
|
-
|
|
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`).
|
|
156
178
|
|
|
157
|
-
|
|
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.
|
|
158
182
|
|
|
159
|
-
|
|
160
|
-
This will allow adding more functionality to `ActiveModel::Model`.
|
|
183
|
+
For example, in the controller, instead of:
|
|
161
184
|
|
|
162
|
-
|
|
185
|
+
```ruby
|
|
186
|
+
password_params = params.require(:password).permit(
|
|
187
|
+
:password_challenge,
|
|
188
|
+
:password,
|
|
189
|
+
:password_confirmation,
|
|
190
|
+
)
|
|
163
191
|
|
|
164
|
-
|
|
192
|
+
password_challenge = password_params.delete(:password_challenge)
|
|
193
|
+
@password_challenge_failed = !current_user.authenticate(password_challenge)
|
|
165
194
|
|
|
166
|
-
|
|
167
|
-
|
|
195
|
+
if !@password_challenge_failed && current_user.update(password_params)
|
|
196
|
+
# ...
|
|
197
|
+
end
|
|
198
|
+
```
|
|
168
199
|
|
|
169
|
-
|
|
200
|
+
You can now write:
|
|
170
201
|
|
|
171
|
-
|
|
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
|
+
```
|
|
172
213
|
|
|
173
|
-
|
|
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`.
|
|
174
217
|
|
|
175
|
-
*
|
|
218
|
+
*Jonathan Hefner*
|
|
176
219
|
|
|
177
|
-
*
|
|
220
|
+
* Support infinite ranges for `LengthValidator`s `:in`/`:within` options
|
|
178
221
|
|
|
179
|
-
|
|
222
|
+
```ruby
|
|
223
|
+
validates_length_of :first_name, in: ..30
|
|
224
|
+
```
|
|
180
225
|
|
|
181
|
-
*
|
|
226
|
+
*fatkodima*
|
|
182
227
|
|
|
183
|
-
*
|
|
228
|
+
* Add support for beginless ranges to inclusivity/exclusivity validators:
|
|
184
229
|
|
|
185
|
-
|
|
230
|
+
```ruby
|
|
231
|
+
validates_inclusion_of :birth_date, in: -> { (..Date.today) }
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
```ruby
|
|
235
|
+
validates_exclusion_of :birth_date, in: -> { (..Date.today) }
|
|
236
|
+
```
|
|
186
237
|
|
|
187
|
-
*
|
|
238
|
+
*Bo Jeanes*
|
|
188
239
|
|
|
189
|
-
*
|
|
240
|
+
* Make validators accept lambdas without record argument
|
|
190
241
|
|
|
191
|
-
|
|
192
|
-
|
|
242
|
+
```ruby
|
|
243
|
+
# Before
|
|
244
|
+
validates_comparison_of :birth_date, less_than_or_equal_to: ->(_record) { Date.today }
|
|
193
245
|
|
|
194
|
-
|
|
246
|
+
# After
|
|
247
|
+
validates_comparison_of :birth_date, less_than_or_equal_to: -> { Date.today }
|
|
248
|
+
```
|
|
195
249
|
|
|
196
|
-
*
|
|
250
|
+
*fatkodima*
|
|
197
251
|
|
|
198
|
-
|
|
252
|
+
* Fix casting long strings to `Date`, `Time` or `DateTime`
|
|
199
253
|
|
|
200
|
-
*
|
|
201
|
-
`plural`, `route_key` and `singular_route_key` values.
|
|
254
|
+
*fatkodima*
|
|
202
255
|
|
|
203
|
-
|
|
256
|
+
* Use different cache namespace for proxy calls
|
|
204
257
|
|
|
205
|
-
|
|
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.
|
|
206
261
|
|
|
207
|
-
*
|
|
262
|
+
*Chris Salzberg*
|
|
208
263
|
|
|
209
|
-
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
|