rbs_rails 0.1.0 → 0.2.0
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/.travis.yml +8 -0
- data/Gemfile +2 -0
- data/LICENSE +201 -0
- data/README.md +52 -5
- data/Rakefile +6 -1
- data/Steepfile +9 -0
- data/assets/sig/action_controller.rbs +44 -0
- data/assets/sig/action_mailer.rbs +5 -0
- data/assets/sig/action_view.rbs +3 -0
- data/assets/sig/active_record.rbs +4 -0
- data/assets/sig/builtin.rbs +7 -0
- data/assets/sig/generated/activemodel.rbs +3877 -0
- data/assets/sig/generated/activesupport.rbs +11480 -0
- data/assets/sig/libxml.rbs +10 -0
- data/assets/sig/minitest.rbs +2 -0
- data/assets/sig/nokogiri.rbs +8 -0
- data/assets/sig/rails.rbs +11 -0
- data/assets/sig/stdlib.rbs +14 -0
- data/bin/add-type-params.rb +59 -0
- data/bin/merge-duplicate-decls.rb +30 -0
- data/lib/rbs_rails.rb +1 -1
- data/lib/rbs_rails/active_record.rb +14 -3
- data/lib/rbs_rails/path_helpers.rb +1 -0
- data/lib/rbs_rails/version.rb +4 -1
- data/rbs_rails.gemspec +1 -0
- data/sig/fileutils.rbs +3 -0
- data/sig/parser.rbs +14 -0
- data/sig/rbs_rails.rbs +6 -0
- data/sig/rbs_rails/active_record.rbs +59 -0
- data/sig/rbs_rails/path_helpers.rbs +11 -0
- data/sig/rbs_rails/version.rbs +1 -0
- metadata +26 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8cc75e64602e5966e87f1bfe2b9530034f81999715b5d9e3697f4f424af9a6da
|
4
|
+
data.tar.gz: 5d742b05e28d190c940d44585883be713133095d17d5778c6e64fbf2ef3b3719
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b07cb43cba9d2bf51beddbfdb45ad4c2e29bc6c80d6301259af7b289c8ab832b2908bbb4d96594cf7ca7d9318c54481c11daf07d6d20dc3826518b40f5b5144
|
7
|
+
data.tar.gz: 2af365f0d0c891d677bd60f4322566aec9897edd93585dfc6871f5ad5923985f9fe8503520b884f98382c5954ca5ab2ce1ec35ed674727449305f35ca1260c02
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
Apache License
|
2
|
+
Version 2.0, January 2004
|
3
|
+
http://www.apache.org/licenses/
|
4
|
+
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
6
|
+
|
7
|
+
1. Definitions.
|
8
|
+
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
11
|
+
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
13
|
+
the copyright owner that is granting the License.
|
14
|
+
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
16
|
+
other entities that control, are controlled by, or are under common
|
17
|
+
control with that entity. For the purposes of this definition,
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
19
|
+
direction or management of such entity, whether by contract or
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
22
|
+
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
24
|
+
exercising permissions granted by this License.
|
25
|
+
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
27
|
+
including but not limited to software source code, documentation
|
28
|
+
source, and configuration files.
|
29
|
+
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
31
|
+
transformation or translation of a Source form, including but
|
32
|
+
not limited to compiled object code, generated documentation,
|
33
|
+
and conversions to other media types.
|
34
|
+
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
36
|
+
Object form, made available under the License, as indicated by a
|
37
|
+
copyright notice that is included in or attached to the work
|
38
|
+
(an example is provided in the Appendix below).
|
39
|
+
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
46
|
+
the Work and Derivative Works thereof.
|
47
|
+
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
49
|
+
the original version of the Work and any modifications or additions
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
61
|
+
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
64
|
+
subsequently incorporated within the Work.
|
65
|
+
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
72
|
+
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
78
|
+
where such license applies only to those patent claims licensable
|
79
|
+
by such Contributor that are necessarily infringed by their
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
82
|
+
institute patent litigation against any entity (including a
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
85
|
+
or contributory patent infringement, then any patent licenses
|
86
|
+
granted to You under this License for that Work shall terminate
|
87
|
+
as of the date such litigation is filed.
|
88
|
+
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
91
|
+
modifications, and in Source or Object form, provided that You
|
92
|
+
meet the following conditions:
|
93
|
+
|
94
|
+
(a) You must give any other recipients of the Work or
|
95
|
+
Derivative Works a copy of this License; and
|
96
|
+
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
98
|
+
stating that You changed the files; and
|
99
|
+
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
102
|
+
attribution notices from the Source form of the Work,
|
103
|
+
excluding those notices that do not pertain to any part of
|
104
|
+
the Derivative Works; and
|
105
|
+
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
108
|
+
include a readable copy of the attribution notices contained
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
111
|
+
of the following places: within a NOTICE text file distributed
|
112
|
+
as part of the Derivative Works; within the Source form or
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
114
|
+
within a display generated by the Derivative Works, if and
|
115
|
+
wherever such third-party notices normally appear. The contents
|
116
|
+
of the NOTICE file are for informational purposes only and
|
117
|
+
do not modify the License. You may add Your own attribution
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
120
|
+
that such additional attribution notices cannot be construed
|
121
|
+
as modifying the License.
|
122
|
+
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
124
|
+
may provide additional or different license terms and conditions
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
128
|
+
the conditions stated in this License.
|
129
|
+
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
133
|
+
this License, without any additional terms or conditions.
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
135
|
+
the terms of any separate license agreement you may have executed
|
136
|
+
with Licensor regarding such Contributions.
|
137
|
+
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
140
|
+
except as required for reasonable and customary use in describing the
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
142
|
+
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
152
|
+
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
158
|
+
incidental, or consequential damages of any character arising as a
|
159
|
+
result of this License or out of the use or inability to use the
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
162
|
+
other commercial damages or losses), even if such Contributor
|
163
|
+
has been advised of the possibility of such damages.
|
164
|
+
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
168
|
+
or other liability obligations and/or rights consistent with this
|
169
|
+
License. However, in accepting such obligations, You may act only
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
174
|
+
of your accepting any such warranty or additional liability.
|
175
|
+
|
176
|
+
END OF TERMS AND CONDITIONS
|
177
|
+
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
179
|
+
|
180
|
+
To apply the Apache License to your work, attach the following
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
182
|
+
replaced with your own identifying information. (Don't include
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
184
|
+
comment syntax for the file format. We also recommend that a
|
185
|
+
file or class name and description of purpose be included on the
|
186
|
+
same "printed page" as the copyright notice for easier
|
187
|
+
identification within third-party archives.
|
188
|
+
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
190
|
+
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
192
|
+
you may not use this file except in compliance with the License.
|
193
|
+
You may obtain a copy of the License at
|
194
|
+
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
196
|
+
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
200
|
+
See the License for the specific language governing permissions and
|
201
|
+
limitations under the License.
|
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# RBS Rails
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
RBS files generator for Ruby on Rails.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
@@ -22,7 +20,56 @@ Or install it yourself as:
|
|
22
20
|
|
23
21
|
## Usage
|
24
22
|
|
25
|
-
|
23
|
+
### For Active Record models
|
24
|
+
|
25
|
+
It has two tasks.
|
26
|
+
|
27
|
+
* `copy_signature_files`: Copy type definition files for Rails from rbs_rails.
|
28
|
+
* `generate_rbs_for_model`: Generate RBS files from model classes.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
# Rakefile
|
32
|
+
|
33
|
+
task copy_signature_files: :environment do
|
34
|
+
require 'rbs_rails'
|
35
|
+
|
36
|
+
to = Rails.root.join('sig/rbs_rails/')
|
37
|
+
to.mkpath unless to.exist?
|
38
|
+
RbsRails.copy_signatures(to: to)
|
39
|
+
end
|
40
|
+
|
41
|
+
task generate_rbs_for_model: :environment do
|
42
|
+
require 'rbs_rails'
|
43
|
+
|
44
|
+
out_dir = Rails.root / 'sig'
|
45
|
+
out_dir.mkdir unless out_dir.exist?
|
46
|
+
|
47
|
+
Rails.application.eager_load!
|
48
|
+
|
49
|
+
ActiveRecord::Base.descendants.each do |klass|
|
50
|
+
next if klass.abstract_class?
|
51
|
+
|
52
|
+
path = out_dir / "app/models/#{klass.name.underscore}.rbs"
|
53
|
+
FileUtils.mkdir_p(path.dirname)
|
54
|
+
|
55
|
+
sig = RbsRails::ActiveRecord.class_to_rbs(klass, mode: :extension)
|
56
|
+
path.write sig
|
57
|
+
end
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
### For path helpers
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
# Rakefile
|
65
|
+
|
66
|
+
task generate_rbs_for_path_helpers: :environment do
|
67
|
+
require 'rbs_rails'
|
68
|
+
out_path = Rails.root.join 'sig/path_helpers.rbs'
|
69
|
+
rbs = RbsRails::PathHelpers.generate
|
70
|
+
out_path.write rbs
|
71
|
+
end
|
72
|
+
```
|
26
73
|
|
27
74
|
## Development
|
28
75
|
|
data/Rakefile
CHANGED
data/Steepfile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
interface _ActionController_API_and_Base
|
2
|
+
def request: () -> untyped
|
3
|
+
def params: () -> untyped
|
4
|
+
def session: () -> untyped
|
5
|
+
def cookies: () -> untyped
|
6
|
+
def flash: () -> untyped
|
7
|
+
def render: (*untyped) -> void
|
8
|
+
def redirect_to: (*untyped) -> void
|
9
|
+
end
|
10
|
+
|
11
|
+
interface _ActionController_API_and_Base_singletion
|
12
|
+
# hooks
|
13
|
+
def before_action: (*untyped) -> void
|
14
|
+
def around_action: (*untyped) -> void
|
15
|
+
def after_action: (*untyped) -> void
|
16
|
+
def skip_before_action: (*untyped) -> void
|
17
|
+
def skip_around_action: (*untyped) -> void
|
18
|
+
def skip_after_action: (*untyped) -> void
|
19
|
+
def prepend_before_action: (*untyped) -> void
|
20
|
+
def prepend_around_action: (*untyped) -> void
|
21
|
+
def prepend_after_action: (*untyped) -> void
|
22
|
+
def append_before_action: (*untyped) -> void
|
23
|
+
def append_around_action: (*untyped) -> void
|
24
|
+
def append_after_action: (*untyped) -> void
|
25
|
+
|
26
|
+
def rescue_from: (*Class, ?with: Symbol | Proc) { (Exception) -> void } -> void
|
27
|
+
end
|
28
|
+
|
29
|
+
class AbstractController::Base
|
30
|
+
end
|
31
|
+
|
32
|
+
class ActionController::Metal < AbstractController::Base
|
33
|
+
end
|
34
|
+
|
35
|
+
class ActionController::Base < ActionController::Metal
|
36
|
+
include _ActionController_API_and_Base
|
37
|
+
extend _ActionController_API_and_Base_singletion
|
38
|
+
extend ActionView::Layouts::ClassMethods
|
39
|
+
end
|
40
|
+
|
41
|
+
class ActionController::API < ActionController::Metal
|
42
|
+
include _ActionController_API_and_Base
|
43
|
+
extend _ActionController_API_and_Base_singletion
|
44
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
class ActiveRecord::Base
|
2
|
+
def self.abstract_class=: (bool) -> void
|
2
3
|
def self.scope: (Symbol, ^(*untyped) -> untyped ) -> void
|
3
4
|
| (Symbol) { (*untyped) -> untyped } -> void
|
4
5
|
def self.belongs_to: (Symbol, ?untyped, **untyped) -> void
|
@@ -28,6 +29,9 @@ class ActiveRecord::Base
|
|
28
29
|
def self.before_update: (*untyped) -> void
|
29
30
|
def self.before_validation: (*untyped) -> void
|
30
31
|
|
32
|
+
def self.columns: () -> Array[untyped]
|
33
|
+
def self.reflect_on_all_associations: (?Symbol) -> Array[untyped]
|
34
|
+
|
31
35
|
def will_save_change_to_attribute?: (String | Symbol attr_name, ?from: untyped, ?to: untyped) -> bool
|
32
36
|
|
33
37
|
def save!: () -> self
|
@@ -0,0 +1,3877 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
# Returns the version of the currently loaded \Active \Model as a <tt>Gem::Version</tt>
|
3
|
+
def self.gem_version: () -> untyped
|
4
|
+
|
5
|
+
extend ActiveSupport::Autoload
|
6
|
+
|
7
|
+
def self.eager_load!: () -> untyped
|
8
|
+
|
9
|
+
# Returns the version of the currently loaded \Active \Model as a <tt>Gem::Version</tt>
|
10
|
+
def self.version: () -> untyped
|
11
|
+
end
|
12
|
+
|
13
|
+
module ActiveModel::AttributeAssignment
|
14
|
+
include ActiveModel::ForbiddenAttributesProtection
|
15
|
+
|
16
|
+
# Allows you to set all the attributes by passing in a hash of attributes with
|
17
|
+
# keys matching the attribute names.
|
18
|
+
#
|
19
|
+
# If the passed hash responds to <tt>permitted?</tt> method and the return value
|
20
|
+
# of this method is +false+ an <tt>ActiveModel::ForbiddenAttributesError</tt>
|
21
|
+
# exception is raised.
|
22
|
+
#
|
23
|
+
# class Cat
|
24
|
+
# include ActiveModel::AttributeAssignment
|
25
|
+
# attr_accessor :name, :status
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# cat = Cat.new
|
29
|
+
# cat.assign_attributes(name: "Gorby", status: "yawning")
|
30
|
+
# cat.name # => 'Gorby'
|
31
|
+
# cat.status # => 'yawning'
|
32
|
+
# cat.assign_attributes(status: "sleeping")
|
33
|
+
# cat.name # => 'Gorby'
|
34
|
+
# cat.status # => 'sleeping'
|
35
|
+
def assign_attributes: (untyped new_attributes) -> (nil | untyped)
|
36
|
+
|
37
|
+
def _assign_attributes: (untyped attributes) -> untyped
|
38
|
+
|
39
|
+
def _assign_attribute: (untyped k, untyped v) -> untyped
|
40
|
+
end
|
41
|
+
|
42
|
+
# Raised when an attribute is not defined.
|
43
|
+
#
|
44
|
+
# class User < ActiveRecord::Base
|
45
|
+
# has_many :pets
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# user = User.first
|
49
|
+
# user.pets.select(:id).first.user_id
|
50
|
+
# # => ActiveModel::MissingAttributeError: missing attribute: user_id
|
51
|
+
class ActiveModel::MissingAttributeError[T] < NoMethodError[T]
|
52
|
+
end
|
53
|
+
|
54
|
+
# == Active \Model \Attribute \Methods
|
55
|
+
#
|
56
|
+
# Provides a way to add prefixes and suffixes to your methods as
|
57
|
+
# well as handling the creation of <tt>ActiveRecord::Base</tt>-like
|
58
|
+
# class methods such as +table_name+.
|
59
|
+
#
|
60
|
+
# The requirements to implement <tt>ActiveModel::AttributeMethods</tt> are to:
|
61
|
+
#
|
62
|
+
# * <tt>include ActiveModel::AttributeMethods</tt> in your class.
|
63
|
+
# * Call each of its methods you want to add, such as +attribute_method_suffix+
|
64
|
+
# or +attribute_method_prefix+.
|
65
|
+
# * Call +define_attribute_methods+ after the other methods are called.
|
66
|
+
# * Define the various generic +_attribute+ methods that you have declared.
|
67
|
+
# * Define an +attributes+ method which returns a hash with each
|
68
|
+
# attribute name in your model as hash key and the attribute value as hash value.
|
69
|
+
# Hash keys must be strings.
|
70
|
+
#
|
71
|
+
# A minimal implementation could be:
|
72
|
+
#
|
73
|
+
# class Person
|
74
|
+
# include ActiveModel::AttributeMethods
|
75
|
+
#
|
76
|
+
# attribute_method_affix prefix: 'reset_', suffix: '_to_default!'
|
77
|
+
# attribute_method_suffix '_contrived?'
|
78
|
+
# attribute_method_prefix 'clear_'
|
79
|
+
# define_attribute_methods :name
|
80
|
+
#
|
81
|
+
# attr_accessor :name
|
82
|
+
#
|
83
|
+
# def attributes
|
84
|
+
# { 'name' => @name }
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# private
|
88
|
+
#
|
89
|
+
# def attribute_contrived?(attr)
|
90
|
+
# true
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# def clear_attribute(attr)
|
94
|
+
# send("#{attr}=", nil)
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# def reset_attribute_to_default!(attr)
|
98
|
+
# send("#{attr}=", 'Default Name')
|
99
|
+
# end
|
100
|
+
# end
|
101
|
+
module ActiveModel::AttributeMethods
|
102
|
+
extend ActiveSupport::Concern
|
103
|
+
|
104
|
+
# Allows access to the object attributes, which are held in the hash
|
105
|
+
# returned by <tt>attributes</tt>, as though they were first-class
|
106
|
+
# methods. So a +Person+ class with a +name+ attribute can for example use
|
107
|
+
# <tt>Person#name</tt> and <tt>Person#name=</tt> and never directly use
|
108
|
+
# the attributes hash -- except for multiple assignments with
|
109
|
+
# <tt>ActiveRecord::Base#attributes=</tt>.
|
110
|
+
#
|
111
|
+
# It's also possible to instantiate related objects, so a <tt>Client</tt>
|
112
|
+
# class belonging to the +clients+ table with a +master_id+ foreign key
|
113
|
+
# can instantiate master through <tt>Client#master</tt>.
|
114
|
+
def method_missing: (untyped method, *untyped args) { () -> untyped } -> untyped
|
115
|
+
|
116
|
+
# +attribute_missing+ is like +method_missing+, but for attributes. When
|
117
|
+
# +method_missing+ is called we check to see if there is a matching
|
118
|
+
# attribute method. If so, we tell +attribute_missing+ to dispatch the
|
119
|
+
# attribute. This method can be overloaded to customize the behavior.
|
120
|
+
def attribute_missing: (untyped match, *untyped args) { () -> untyped } -> untyped
|
121
|
+
|
122
|
+
def respond_to?: (untyped method, ?bool include_private_methods) -> untyped
|
123
|
+
|
124
|
+
def attribute_method?: (untyped attr_name) -> untyped
|
125
|
+
|
126
|
+
# Returns a struct representing the matching attribute method.
|
127
|
+
# The struct's attributes are prefix, base and suffix.
|
128
|
+
def matched_attribute_method: (untyped method_name) -> untyped
|
129
|
+
|
130
|
+
def missing_attribute: (untyped attr_name, untyped stack) -> untyped
|
131
|
+
|
132
|
+
def _read_attribute: (untyped attr) -> untyped
|
133
|
+
end
|
134
|
+
|
135
|
+
ActiveModel::AttributeMethods::NAME_COMPILABLE_REGEXP: untyped
|
136
|
+
|
137
|
+
ActiveModel::AttributeMethods::CALL_COMPILABLE_REGEXP: untyped
|
138
|
+
|
139
|
+
module ActiveModel::AttributeMethods::ClassMethods
|
140
|
+
# Declares a method available for all attributes with the given prefix.
|
141
|
+
# Uses +method_missing+ and <tt>respond_to?</tt> to rewrite the method.
|
142
|
+
#
|
143
|
+
# #{prefix}#{attr}(*args, &block)
|
144
|
+
#
|
145
|
+
# to
|
146
|
+
#
|
147
|
+
# #{prefix}attribute(#{attr}, *args, &block)
|
148
|
+
#
|
149
|
+
# An instance method <tt>#{prefix}attribute</tt> must exist and accept
|
150
|
+
# at least the +attr+ argument.
|
151
|
+
#
|
152
|
+
# class Person
|
153
|
+
# include ActiveModel::AttributeMethods
|
154
|
+
#
|
155
|
+
# attr_accessor :name
|
156
|
+
# attribute_method_prefix 'clear_'
|
157
|
+
# define_attribute_methods :name
|
158
|
+
#
|
159
|
+
# private
|
160
|
+
#
|
161
|
+
# def clear_attribute(attr)
|
162
|
+
# send("#{attr}=", nil)
|
163
|
+
# end
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# person = Person.new
|
167
|
+
# person.name = 'Bob'
|
168
|
+
# person.name # => "Bob"
|
169
|
+
# person.clear_name
|
170
|
+
# person.name # => nil
|
171
|
+
def attribute_method_prefix: (*untyped prefixes) -> untyped
|
172
|
+
|
173
|
+
# Declares a method available for all attributes with the given suffix.
|
174
|
+
# Uses +method_missing+ and <tt>respond_to?</tt> to rewrite the method.
|
175
|
+
#
|
176
|
+
# #{attr}#{suffix}(*args, &block)
|
177
|
+
#
|
178
|
+
# to
|
179
|
+
#
|
180
|
+
# attribute#{suffix}(#{attr}, *args, &block)
|
181
|
+
#
|
182
|
+
# An <tt>attribute#{suffix}</tt> instance method must exist and accept at
|
183
|
+
# least the +attr+ argument.
|
184
|
+
#
|
185
|
+
# class Person
|
186
|
+
# include ActiveModel::AttributeMethods
|
187
|
+
#
|
188
|
+
# attr_accessor :name
|
189
|
+
# attribute_method_suffix '_short?'
|
190
|
+
# define_attribute_methods :name
|
191
|
+
#
|
192
|
+
# private
|
193
|
+
#
|
194
|
+
# def attribute_short?(attr)
|
195
|
+
# send(attr).length < 5
|
196
|
+
# end
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# person = Person.new
|
200
|
+
# person.name = 'Bob'
|
201
|
+
# person.name # => "Bob"
|
202
|
+
# person.name_short? # => true
|
203
|
+
def attribute_method_suffix: (*untyped suffixes) -> untyped
|
204
|
+
|
205
|
+
# Declares a method available for all attributes with the given prefix
|
206
|
+
# and suffix. Uses +method_missing+ and <tt>respond_to?</tt> to rewrite
|
207
|
+
# the method.
|
208
|
+
#
|
209
|
+
# #{prefix}#{attr}#{suffix}(*args, &block)
|
210
|
+
#
|
211
|
+
# to
|
212
|
+
#
|
213
|
+
# #{prefix}attribute#{suffix}(#{attr}, *args, &block)
|
214
|
+
#
|
215
|
+
# An <tt>#{prefix}attribute#{suffix}</tt> instance method must exist and
|
216
|
+
# accept at least the +attr+ argument.
|
217
|
+
#
|
218
|
+
# class Person
|
219
|
+
# include ActiveModel::AttributeMethods
|
220
|
+
#
|
221
|
+
# attr_accessor :name
|
222
|
+
# attribute_method_affix prefix: 'reset_', suffix: '_to_default!'
|
223
|
+
# define_attribute_methods :name
|
224
|
+
#
|
225
|
+
# private
|
226
|
+
#
|
227
|
+
# def reset_attribute_to_default!(attr)
|
228
|
+
# send("#{attr}=", 'Default Name')
|
229
|
+
# end
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
# person = Person.new
|
233
|
+
# person.name # => 'Gem'
|
234
|
+
# person.reset_name_to_default!
|
235
|
+
# person.name # => 'Default Name'
|
236
|
+
def attribute_method_affix: (*untyped affixes) -> untyped
|
237
|
+
|
238
|
+
# Allows you to make aliases for attributes.
|
239
|
+
#
|
240
|
+
# class Person
|
241
|
+
# include ActiveModel::AttributeMethods
|
242
|
+
#
|
243
|
+
# attr_accessor :name
|
244
|
+
# attribute_method_suffix '_short?'
|
245
|
+
# define_attribute_methods :name
|
246
|
+
#
|
247
|
+
# alias_attribute :nickname, :name
|
248
|
+
#
|
249
|
+
# private
|
250
|
+
#
|
251
|
+
# def attribute_short?(attr)
|
252
|
+
# send(attr).length < 5
|
253
|
+
# end
|
254
|
+
# end
|
255
|
+
#
|
256
|
+
# person = Person.new
|
257
|
+
# person.name = 'Bob'
|
258
|
+
# person.name # => "Bob"
|
259
|
+
# person.nickname # => "Bob"
|
260
|
+
# person.name_short? # => true
|
261
|
+
# person.nickname_short? # => true
|
262
|
+
def alias_attribute: (untyped new_name, untyped old_name) -> untyped
|
263
|
+
|
264
|
+
# Is +new_name+ an alias?
|
265
|
+
def attribute_alias?: (untyped new_name) -> untyped
|
266
|
+
|
267
|
+
# Returns the original name for the alias +name+
|
268
|
+
def attribute_alias: (untyped name) -> untyped
|
269
|
+
|
270
|
+
# Declares the attributes that should be prefixed and suffixed by
|
271
|
+
# <tt>ActiveModel::AttributeMethods</tt>.
|
272
|
+
#
|
273
|
+
# To use, pass attribute names (as strings or symbols). Be sure to declare
|
274
|
+
# +define_attribute_methods+ after you define any prefix, suffix or affix
|
275
|
+
# methods, or they will not hook in.
|
276
|
+
#
|
277
|
+
# class Person
|
278
|
+
# include ActiveModel::AttributeMethods
|
279
|
+
#
|
280
|
+
# attr_accessor :name, :age, :address
|
281
|
+
# attribute_method_prefix 'clear_'
|
282
|
+
#
|
283
|
+
# # Call to define_attribute_methods must appear after the
|
284
|
+
# # attribute_method_prefix, attribute_method_suffix or
|
285
|
+
# # attribute_method_affix declarations.
|
286
|
+
# define_attribute_methods :name, :age, :address
|
287
|
+
#
|
288
|
+
# private
|
289
|
+
#
|
290
|
+
# def clear_attribute(attr)
|
291
|
+
# send("#{attr}=", nil)
|
292
|
+
# end
|
293
|
+
# end
|
294
|
+
def define_attribute_methods: (*untyped attr_names) -> untyped
|
295
|
+
|
296
|
+
# Declares an attribute that should be prefixed and suffixed by
|
297
|
+
# <tt>ActiveModel::AttributeMethods</tt>.
|
298
|
+
#
|
299
|
+
# To use, pass an attribute name (as string or symbol). Be sure to declare
|
300
|
+
# +define_attribute_method+ after you define any prefix, suffix or affix
|
301
|
+
# method, or they will not hook in.
|
302
|
+
#
|
303
|
+
# class Person
|
304
|
+
# include ActiveModel::AttributeMethods
|
305
|
+
#
|
306
|
+
# attr_accessor :name
|
307
|
+
# attribute_method_suffix '_short?'
|
308
|
+
#
|
309
|
+
# # Call to define_attribute_method must appear after the
|
310
|
+
# # attribute_method_prefix, attribute_method_suffix or
|
311
|
+
# # attribute_method_affix declarations.
|
312
|
+
# define_attribute_method :name
|
313
|
+
#
|
314
|
+
# private
|
315
|
+
#
|
316
|
+
# def attribute_short?(attr)
|
317
|
+
# send(attr).length < 5
|
318
|
+
# end
|
319
|
+
# end
|
320
|
+
#
|
321
|
+
# person = Person.new
|
322
|
+
# person.name = 'Bob'
|
323
|
+
# person.name # => "Bob"
|
324
|
+
# person.name_short? # => true
|
325
|
+
def define_attribute_method: (untyped attr_name) -> untyped
|
326
|
+
|
327
|
+
# Removes all the previously dynamically defined methods from the class.
|
328
|
+
#
|
329
|
+
# class Person
|
330
|
+
# include ActiveModel::AttributeMethods
|
331
|
+
#
|
332
|
+
# attr_accessor :name
|
333
|
+
# attribute_method_suffix '_short?'
|
334
|
+
# define_attribute_method :name
|
335
|
+
#
|
336
|
+
# private
|
337
|
+
#
|
338
|
+
# def attribute_short?(attr)
|
339
|
+
# send(attr).length < 5
|
340
|
+
# end
|
341
|
+
# end
|
342
|
+
#
|
343
|
+
# person = Person.new
|
344
|
+
# person.name = 'Bob'
|
345
|
+
# person.name_short? # => true
|
346
|
+
#
|
347
|
+
# Person.undefine_attribute_methods
|
348
|
+
#
|
349
|
+
# person.name_short? # => NoMethodError
|
350
|
+
def undefine_attribute_methods: () -> untyped
|
351
|
+
|
352
|
+
def generated_attribute_methods: () -> untyped
|
353
|
+
|
354
|
+
def instance_method_already_implemented?: (untyped method_name) -> untyped
|
355
|
+
|
356
|
+
# The methods +method_missing+ and +respond_to?+ of this module are
|
357
|
+
# invoked often in a typical rails, both of which invoke the method
|
358
|
+
# +matched_attribute_method+. The latter method iterates through an
|
359
|
+
# array doing regular expression matches, which results in a lot of
|
360
|
+
# object creations. Most of the time it returns a +nil+ match. As the
|
361
|
+
# match result is always the same given a +method_name+, this cache is
|
362
|
+
# used to alleviate the GC, which ultimately also speeds up the app
|
363
|
+
# significantly (in our case our test suite finishes 10% faster with
|
364
|
+
# this cache).
|
365
|
+
def attribute_method_matchers_cache: () -> untyped
|
366
|
+
|
367
|
+
def attribute_method_matchers_matching: (untyped method_name) -> untyped
|
368
|
+
|
369
|
+
# Define a method `name` in `mod` that dispatches to `send`
|
370
|
+
# using the given `extra` args. This falls back on `define_method`
|
371
|
+
# and `send` if the given names cannot be compiled.
|
372
|
+
def define_proxy_call: (untyped include_private, untyped mod, untyped name, untyped target, *untyped extra) -> untyped
|
373
|
+
end
|
374
|
+
|
375
|
+
class ActiveModel::AttributeMethods::ClassMethods::AttributeMethodMatcher
|
376
|
+
# nodoc:
|
377
|
+
attr_reader prefix: untyped
|
378
|
+
|
379
|
+
# nodoc:
|
380
|
+
attr_reader suffix: untyped
|
381
|
+
|
382
|
+
# nodoc:
|
383
|
+
attr_reader target: untyped
|
384
|
+
|
385
|
+
def initialize: (?::Hash[untyped, untyped] options) -> untyped
|
386
|
+
|
387
|
+
def match: (untyped method_name) -> untyped
|
388
|
+
|
389
|
+
def method_name: (untyped attr_name) -> untyped
|
390
|
+
|
391
|
+
def plain?: () -> untyped
|
392
|
+
end
|
393
|
+
|
394
|
+
ActiveModel::AttributeMethods::ClassMethods::AttributeMethodMatcher::AttributeMethodMatch: untyped
|
395
|
+
|
396
|
+
module ActiveModel::AttributeMethods::AttrNames
|
397
|
+
# We want to generate the methods via module_eval rather than
|
398
|
+
# define_method, because define_method is slower on dispatch.
|
399
|
+
# Evaluating many similar methods may use more memory as the instruction
|
400
|
+
# sequences are duplicated and cached (in MRI). define_method may
|
401
|
+
# be slower on dispatch, but if you're careful about the closure
|
402
|
+
# created, then define_method will consume much less memory.
|
403
|
+
#
|
404
|
+
# But sometimes the database might return columns with
|
405
|
+
# characters that are not allowed in normal method names (like
|
406
|
+
# 'my_column(omg)'. So to work around this we first define with
|
407
|
+
# the __temp__ identifier, and then use alias method to rename
|
408
|
+
# it to what we want.
|
409
|
+
#
|
410
|
+
# We are also defining a constant to hold the frozen string of
|
411
|
+
# the attribute name. Using a constant means that we do not have
|
412
|
+
# to allocate an object on each call to the attribute method.
|
413
|
+
# Making it frozen means that it doesn't get duped when used to
|
414
|
+
# key the @attributes in read_attribute.
|
415
|
+
def self.define_attribute_accessor_method: (untyped mod, untyped attr_name, ?writer: bool writer) { (untyped, untyped) -> untyped } -> untyped
|
416
|
+
end
|
417
|
+
|
418
|
+
# :nodoc:
|
419
|
+
ActiveModel::AttributeMethods::AttrNames::DEF_SAFE_NAME: untyped
|
420
|
+
|
421
|
+
class ActiveModel::AttributeMutationTracker
|
422
|
+
def initialize: (untyped attributes, ?untyped forced_changes) -> untyped
|
423
|
+
|
424
|
+
def changed_attribute_names: () -> untyped
|
425
|
+
|
426
|
+
def changed_values: () -> untyped
|
427
|
+
|
428
|
+
def changes: () -> untyped
|
429
|
+
|
430
|
+
def change_to_attribute: (untyped attr_name) -> untyped
|
431
|
+
|
432
|
+
def any_changes?: () -> untyped
|
433
|
+
|
434
|
+
def changed?: (untyped attr_name, ?to: untyped to, ?from: untyped from) -> untyped
|
435
|
+
|
436
|
+
def changed_in_place?: (untyped attr_name) -> untyped
|
437
|
+
|
438
|
+
def forget_change: (untyped attr_name) -> untyped
|
439
|
+
|
440
|
+
def original_value: (untyped attr_name) -> untyped
|
441
|
+
|
442
|
+
def force_change: (untyped attr_name) -> untyped
|
443
|
+
|
444
|
+
attr_reader attributes: untyped
|
445
|
+
|
446
|
+
attr_reader forced_changes: untyped
|
447
|
+
|
448
|
+
def attr_names: () -> untyped
|
449
|
+
|
450
|
+
def attribute_changed?: (untyped attr_name) -> untyped
|
451
|
+
|
452
|
+
def fetch_value: (untyped attr_name) -> untyped
|
453
|
+
end
|
454
|
+
|
455
|
+
# :nodoc:
|
456
|
+
ActiveModel::AttributeMutationTracker::OPTION_NOT_GIVEN: untyped
|
457
|
+
|
458
|
+
class ActiveModel::ForcedMutationTracker < AttributeMutationTracker
|
459
|
+
# :nodoc:
|
460
|
+
def initialize: (untyped attributes, ?::Hash[untyped, untyped] forced_changes) -> untyped
|
461
|
+
|
462
|
+
def changed_in_place?: (untyped attr_name) -> ::FalseClass
|
463
|
+
|
464
|
+
def change_to_attribute: (untyped attr_name) -> untyped
|
465
|
+
|
466
|
+
def forget_change: (untyped attr_name) -> untyped
|
467
|
+
|
468
|
+
def original_value: (untyped attr_name) -> untyped
|
469
|
+
|
470
|
+
def force_change: (untyped attr_name) -> untyped
|
471
|
+
|
472
|
+
def finalize_changes: () -> untyped
|
473
|
+
|
474
|
+
attr_reader finalized_changes: untyped
|
475
|
+
|
476
|
+
def attr_names: () -> untyped
|
477
|
+
|
478
|
+
def attribute_changed?: (untyped attr_name) -> untyped
|
479
|
+
|
480
|
+
def fetch_value: (untyped attr_name) -> untyped
|
481
|
+
|
482
|
+
def clone_value: (untyped attr_name) -> untyped
|
483
|
+
end
|
484
|
+
|
485
|
+
class ActiveModel::NullMutationTracker
|
486
|
+
# :nodoc:
|
487
|
+
include Singleton
|
488
|
+
|
489
|
+
def changed_attribute_names: () -> ::Array[untyped]
|
490
|
+
|
491
|
+
def changed_values: () -> ::Hash[untyped, untyped]
|
492
|
+
|
493
|
+
def changes: () -> ::Hash[untyped, untyped]
|
494
|
+
|
495
|
+
def change_to_attribute: (untyped attr_name) -> nil
|
496
|
+
|
497
|
+
def any_changes?: () -> ::FalseClass
|
498
|
+
|
499
|
+
def changed?: (untyped attr_name) -> ::FalseClass
|
500
|
+
|
501
|
+
def changed_in_place?: (untyped attr_name) -> ::FalseClass
|
502
|
+
|
503
|
+
def original_value: (untyped attr_name) -> nil
|
504
|
+
end
|
505
|
+
|
506
|
+
class ActiveModel::Attribute
|
507
|
+
def self.from_database: (untyped name, untyped value, untyped `type`) -> untyped
|
508
|
+
|
509
|
+
def self.from_user: (untyped name, untyped value, untyped `type`, ?untyped? original_attribute) -> untyped
|
510
|
+
|
511
|
+
def self.with_cast_value: (untyped name, untyped value, untyped `type`) -> untyped
|
512
|
+
|
513
|
+
def self.null: (untyped name) -> untyped
|
514
|
+
|
515
|
+
def self.uninitialized: (untyped name, untyped `type`) -> untyped
|
516
|
+
|
517
|
+
attr_reader name: untyped
|
518
|
+
|
519
|
+
attr_reader value_before_type_cast: untyped
|
520
|
+
|
521
|
+
attr_reader type: untyped
|
522
|
+
|
523
|
+
# This method should not be called directly.
|
524
|
+
# Use #from_database or #from_user
|
525
|
+
def initialize: (untyped name, untyped value_before_type_cast, untyped `type`, ?untyped? original_attribute) -> untyped
|
526
|
+
|
527
|
+
def value: () -> untyped
|
528
|
+
|
529
|
+
def original_value: () -> untyped
|
530
|
+
|
531
|
+
def value_for_database: () -> untyped
|
532
|
+
|
533
|
+
def changed?: () -> untyped
|
534
|
+
|
535
|
+
def changed_in_place?: () -> untyped
|
536
|
+
|
537
|
+
def forgetting_assignment: () -> untyped
|
538
|
+
|
539
|
+
def with_value_from_user: (untyped value) -> untyped
|
540
|
+
|
541
|
+
def with_value_from_database: (untyped value) -> untyped
|
542
|
+
|
543
|
+
def with_cast_value: (untyped value) -> untyped
|
544
|
+
|
545
|
+
def with_type: (untyped `type`) -> untyped
|
546
|
+
|
547
|
+
def type_cast: () -> untyped
|
548
|
+
|
549
|
+
def initialized?: () -> ::TrueClass
|
550
|
+
|
551
|
+
def came_from_user?: () -> ::FalseClass
|
552
|
+
|
553
|
+
def has_been_read?: () -> untyped
|
554
|
+
|
555
|
+
def ==: (untyped other) -> untyped
|
556
|
+
|
557
|
+
def hash: () -> untyped
|
558
|
+
|
559
|
+
def init_with: (untyped coder) -> untyped
|
560
|
+
|
561
|
+
def encode_with: (untyped coder) -> untyped
|
562
|
+
|
563
|
+
def original_value_for_database: () -> untyped
|
564
|
+
|
565
|
+
attr_reader original_attribute: untyped
|
566
|
+
|
567
|
+
def initialize_dup: (untyped other) -> untyped
|
568
|
+
|
569
|
+
def changed_from_assignment?: () -> untyped
|
570
|
+
|
571
|
+
def _original_value_for_database: () -> untyped
|
572
|
+
end
|
573
|
+
|
574
|
+
class ActiveModel::Attribute::FromDatabase < Attribute
|
575
|
+
# :nodoc:
|
576
|
+
def type_cast: (untyped value) -> untyped
|
577
|
+
|
578
|
+
def _original_value_for_database: () -> untyped
|
579
|
+
end
|
580
|
+
|
581
|
+
class ActiveModel::Attribute::FromUser < Attribute
|
582
|
+
# :nodoc:
|
583
|
+
def type_cast: (untyped value) -> untyped
|
584
|
+
|
585
|
+
def came_from_user?: () -> untyped
|
586
|
+
end
|
587
|
+
|
588
|
+
class ActiveModel::Attribute::WithCastValue < Attribute
|
589
|
+
# :nodoc:
|
590
|
+
def type_cast: (untyped value) -> untyped
|
591
|
+
|
592
|
+
def changed_in_place?: () -> ::FalseClass
|
593
|
+
end
|
594
|
+
|
595
|
+
class ActiveModel::Attribute::Null < Attribute
|
596
|
+
# :nodoc:
|
597
|
+
def initialize: (untyped name) -> untyped
|
598
|
+
|
599
|
+
def type_cast: () -> nil
|
600
|
+
|
601
|
+
def with_type: (untyped `type`) -> untyped
|
602
|
+
|
603
|
+
def with_value_from_database: (untyped value) -> untyped
|
604
|
+
end
|
605
|
+
|
606
|
+
class ActiveModel::Attribute::Uninitialized < Attribute
|
607
|
+
def initialize: (untyped name, untyped `type`) -> untyped
|
608
|
+
|
609
|
+
def value: () { (untyped) -> untyped } -> untyped
|
610
|
+
|
611
|
+
def original_value: () -> untyped
|
612
|
+
|
613
|
+
def value_for_database: () -> nil
|
614
|
+
|
615
|
+
def initialized?: () -> ::FalseClass
|
616
|
+
|
617
|
+
def forgetting_assignment: () -> untyped
|
618
|
+
|
619
|
+
def with_type: (untyped `type`) -> untyped
|
620
|
+
end
|
621
|
+
|
622
|
+
# :nodoc:
|
623
|
+
ActiveModel::Attribute::Uninitialized::UNINITIALIZED_ORIGINAL_VALUE: untyped
|
624
|
+
|
625
|
+
class ActiveModel::AttributeSet
|
626
|
+
def initialize: (untyped attributes) -> untyped
|
627
|
+
|
628
|
+
def []: (untyped name) -> untyped
|
629
|
+
|
630
|
+
def []=: (untyped name, untyped value) -> untyped
|
631
|
+
|
632
|
+
def values_before_type_cast: () -> untyped
|
633
|
+
|
634
|
+
def to_hash: () -> untyped
|
635
|
+
|
636
|
+
def key?: (untyped name) -> untyped
|
637
|
+
|
638
|
+
def keys: () -> untyped
|
639
|
+
|
640
|
+
def fetch_value: (untyped name) { () -> untyped } -> untyped
|
641
|
+
|
642
|
+
def write_from_database: (untyped name, untyped value) -> untyped
|
643
|
+
|
644
|
+
def write_from_user: (untyped name, untyped value) -> untyped
|
645
|
+
|
646
|
+
def write_cast_value: (untyped name, untyped value) -> untyped
|
647
|
+
|
648
|
+
def freeze: () -> untyped
|
649
|
+
|
650
|
+
def deep_dup: () -> untyped
|
651
|
+
|
652
|
+
def initialize_dup: (untyped _) -> untyped
|
653
|
+
|
654
|
+
def initialize_clone: (untyped _) -> untyped
|
655
|
+
|
656
|
+
def reset: (untyped key) -> untyped
|
657
|
+
|
658
|
+
def accessed: () -> untyped
|
659
|
+
|
660
|
+
def map: () { () -> untyped } -> untyped
|
661
|
+
|
662
|
+
def ==: (untyped other) -> untyped
|
663
|
+
|
664
|
+
attr_reader attributes: untyped
|
665
|
+
|
666
|
+
def initialized_attributes: () -> untyped
|
667
|
+
end
|
668
|
+
|
669
|
+
class ActiveModel::AttributeSet::Builder
|
670
|
+
# :nodoc:
|
671
|
+
# :nodoc:
|
672
|
+
attr_reader types: untyped
|
673
|
+
|
674
|
+
# :nodoc:
|
675
|
+
# :nodoc:
|
676
|
+
attr_reader default_attributes: untyped
|
677
|
+
|
678
|
+
def initialize: (untyped types, ?::Hash[untyped, untyped] default_attributes) -> untyped
|
679
|
+
|
680
|
+
def build_from_database: (?::Hash[untyped, untyped] values, ?::Hash[untyped, untyped] additional_types) -> untyped
|
681
|
+
end
|
682
|
+
|
683
|
+
class ActiveModel::LazyAttributeHash
|
684
|
+
def initialize: (untyped types, untyped values, untyped additional_types, untyped default_attributes, ?::Hash[untyped, untyped] delegate_hash) -> untyped
|
685
|
+
|
686
|
+
def key?: (untyped key) -> untyped
|
687
|
+
|
688
|
+
def []: (untyped key) -> untyped
|
689
|
+
|
690
|
+
def []=: (untyped key, untyped value) -> untyped
|
691
|
+
|
692
|
+
def deep_dup: () -> untyped
|
693
|
+
|
694
|
+
def initialize_dup: (untyped _) -> untyped
|
695
|
+
|
696
|
+
def select: () { (untyped, untyped) -> untyped } -> untyped
|
697
|
+
|
698
|
+
def ==: (untyped other) -> untyped
|
699
|
+
|
700
|
+
def marshal_dump: () -> ::Array[untyped]
|
701
|
+
|
702
|
+
def marshal_load: (untyped values) -> untyped
|
703
|
+
|
704
|
+
def materialize: () -> untyped
|
705
|
+
|
706
|
+
attr_reader types: untyped
|
707
|
+
|
708
|
+
attr_reader values: untyped
|
709
|
+
|
710
|
+
attr_reader additional_types: untyped
|
711
|
+
|
712
|
+
attr_reader delegate_hash: untyped
|
713
|
+
|
714
|
+
attr_reader default_attributes: untyped
|
715
|
+
|
716
|
+
def assign_default_value: (untyped name) -> untyped
|
717
|
+
end
|
718
|
+
|
719
|
+
class ActiveModel::AttributeSet::YAMLEncoder
|
720
|
+
# Attempts to do more intelligent YAML dumping of an
|
721
|
+
# ActiveModel::AttributeSet to reduce the size of the resulting string
|
722
|
+
# :nodoc:
|
723
|
+
def initialize: (untyped default_types) -> untyped
|
724
|
+
|
725
|
+
def encode: (untyped attribute_set, untyped coder) -> untyped
|
726
|
+
|
727
|
+
def decode: (untyped coder) -> untyped
|
728
|
+
|
729
|
+
attr_reader default_types: untyped
|
730
|
+
end
|
731
|
+
|
732
|
+
module ActiveModel::Attributes
|
733
|
+
# nodoc:
|
734
|
+
extend ActiveSupport::Concern
|
735
|
+
|
736
|
+
include ActiveModel::AttributeMethods
|
737
|
+
|
738
|
+
def initialize: () -> untyped
|
739
|
+
|
740
|
+
# Returns a hash of all the attributes with their names as keys and the values of the attributes as values.
|
741
|
+
#
|
742
|
+
# class Person
|
743
|
+
# include ActiveModel::Model
|
744
|
+
# include ActiveModel::Attributes
|
745
|
+
#
|
746
|
+
# attribute :name, :string
|
747
|
+
# attribute :age, :integer
|
748
|
+
# end
|
749
|
+
#
|
750
|
+
# person = Person.new(name: 'Francesco', age: 22)
|
751
|
+
# person.attributes
|
752
|
+
# # => {"name"=>"Francesco", "age"=>22}
|
753
|
+
def attributes: () -> untyped
|
754
|
+
|
755
|
+
# Returns an array of attribute names as strings
|
756
|
+
#
|
757
|
+
# class Person
|
758
|
+
# include ActiveModel::Attributes
|
759
|
+
#
|
760
|
+
# attribute :name, :string
|
761
|
+
# attribute :age, :integer
|
762
|
+
# end
|
763
|
+
#
|
764
|
+
# person = Person.new
|
765
|
+
# person.attribute_names
|
766
|
+
# # => ["name", "age"]
|
767
|
+
def attribute_names: () -> untyped
|
768
|
+
|
769
|
+
def write_attribute: (untyped attr_name, untyped value) -> untyped
|
770
|
+
|
771
|
+
def attribute: (untyped attr_name) -> untyped
|
772
|
+
|
773
|
+
# Dispatch target for <tt>*=</tt> attribute methods.
|
774
|
+
def attribute=: (untyped attribute_name, untyped value) -> untyped
|
775
|
+
end
|
776
|
+
|
777
|
+
module ActiveModel::Attributes::ClassMethods
|
778
|
+
def attribute: (untyped name, ?untyped `type`, **untyped options) -> untyped
|
779
|
+
|
780
|
+
# Returns an array of attribute names as strings
|
781
|
+
#
|
782
|
+
# class Person
|
783
|
+
# include ActiveModel::Attributes
|
784
|
+
#
|
785
|
+
# attribute :name, :string
|
786
|
+
# attribute :age, :integer
|
787
|
+
# end
|
788
|
+
#
|
789
|
+
# Person.attribute_names
|
790
|
+
# # => ["name", "age"]
|
791
|
+
def attribute_names: () -> untyped
|
792
|
+
|
793
|
+
def define_method_attribute=: (untyped name) -> untyped
|
794
|
+
|
795
|
+
def define_default_attribute: (untyped name, untyped value, untyped `type`) -> untyped
|
796
|
+
end
|
797
|
+
|
798
|
+
ActiveModel::Attributes::ClassMethods::NO_DEFAULT_PROVIDED: untyped
|
799
|
+
|
800
|
+
class ActiveModel::Attribute::UserProvidedDefault < FromUser
|
801
|
+
# :nodoc:
|
802
|
+
# :nodoc:
|
803
|
+
def initialize: (untyped name, untyped value, untyped `type`, untyped database_default) -> untyped
|
804
|
+
|
805
|
+
def value_before_type_cast: () -> untyped
|
806
|
+
|
807
|
+
def with_type: (untyped `type`) -> untyped
|
808
|
+
|
809
|
+
def marshal_dump: () -> untyped
|
810
|
+
|
811
|
+
def marshal_load: (untyped values) -> untyped
|
812
|
+
|
813
|
+
attr_reader user_provided_value: untyped
|
814
|
+
end
|
815
|
+
|
816
|
+
# == Active \Model \Callbacks
|
817
|
+
#
|
818
|
+
# Provides an interface for any class to have Active Record like callbacks.
|
819
|
+
#
|
820
|
+
# Like the Active Record methods, the callback chain is aborted as soon as
|
821
|
+
# one of the methods throws +:abort+.
|
822
|
+
#
|
823
|
+
# First, extend ActiveModel::Callbacks from the class you are creating:
|
824
|
+
#
|
825
|
+
# class MyModel
|
826
|
+
# extend ActiveModel::Callbacks
|
827
|
+
# end
|
828
|
+
#
|
829
|
+
# Then define a list of methods that you want callbacks attached to:
|
830
|
+
#
|
831
|
+
# define_model_callbacks :create, :update
|
832
|
+
#
|
833
|
+
# This will provide all three standard callbacks (before, around and after)
|
834
|
+
# for both the <tt>:create</tt> and <tt>:update</tt> methods. To implement,
|
835
|
+
# you need to wrap the methods you want callbacks on in a block so that the
|
836
|
+
# callbacks get a chance to fire:
|
837
|
+
#
|
838
|
+
# def create
|
839
|
+
# run_callbacks :create do
|
840
|
+
# # Your create action methods here
|
841
|
+
# end
|
842
|
+
# end
|
843
|
+
#
|
844
|
+
# Then in your class, you can use the +before_create+, +after_create+ and
|
845
|
+
# +around_create+ methods, just as you would in an Active Record model.
|
846
|
+
#
|
847
|
+
# before_create :action_before_create
|
848
|
+
#
|
849
|
+
# def action_before_create
|
850
|
+
# # Your code here
|
851
|
+
# end
|
852
|
+
#
|
853
|
+
# When defining an around callback remember to yield to the block, otherwise
|
854
|
+
# it won't be executed:
|
855
|
+
#
|
856
|
+
# around_create :log_status
|
857
|
+
#
|
858
|
+
# def log_status
|
859
|
+
# puts 'going to call the block...'
|
860
|
+
# yield
|
861
|
+
# puts 'block successfully called.'
|
862
|
+
# end
|
863
|
+
#
|
864
|
+
# You can choose to have only specific callbacks by passing a hash to the
|
865
|
+
# +define_model_callbacks+ method.
|
866
|
+
#
|
867
|
+
# define_model_callbacks :create, only: [:after, :before]
|
868
|
+
#
|
869
|
+
# Would only create the +after_create+ and +before_create+ callback methods in
|
870
|
+
# your class.
|
871
|
+
#
|
872
|
+
# NOTE: Calling the same callback multiple times will overwrite previous callback definitions.
|
873
|
+
#
|
874
|
+
module ActiveModel::Callbacks
|
875
|
+
def self.extended: (untyped base) -> untyped
|
876
|
+
|
877
|
+
# define_model_callbacks accepts the same options +define_callbacks+ does,
|
878
|
+
# in case you want to overwrite a default. Besides that, it also accepts an
|
879
|
+
# <tt>:only</tt> option, where you can choose if you want all types (before,
|
880
|
+
# around or after) or just some.
|
881
|
+
#
|
882
|
+
# define_model_callbacks :initializer, only: :after
|
883
|
+
#
|
884
|
+
# Note, the <tt>only: <type></tt> hash will apply to all callbacks defined
|
885
|
+
# on that method call. To get around this you can call the define_model_callbacks
|
886
|
+
# method as many times as you need.
|
887
|
+
#
|
888
|
+
# define_model_callbacks :create, only: :after
|
889
|
+
# define_model_callbacks :update, only: :before
|
890
|
+
# define_model_callbacks :destroy, only: :around
|
891
|
+
#
|
892
|
+
# Would create +after_create+, +before_update+ and +around_destroy+ methods
|
893
|
+
# only.
|
894
|
+
#
|
895
|
+
# You can pass in a class to before_<type>, after_<type> and around_<type>,
|
896
|
+
# in which case the callback will call that class's <action>_<type> method
|
897
|
+
# passing the object that the callback is being called on.
|
898
|
+
#
|
899
|
+
# class MyModel
|
900
|
+
# extend ActiveModel::Callbacks
|
901
|
+
# define_model_callbacks :create
|
902
|
+
#
|
903
|
+
# before_create AnotherClass
|
904
|
+
# end
|
905
|
+
#
|
906
|
+
# class AnotherClass
|
907
|
+
# def self.before_create( obj )
|
908
|
+
# # obj is the MyModel instance that the callback is being called on
|
909
|
+
# end
|
910
|
+
# end
|
911
|
+
#
|
912
|
+
# NOTE: +method_name+ passed to define_model_callbacks must not end with
|
913
|
+
# <tt>!</tt>, <tt>?</tt> or <tt>=</tt>.
|
914
|
+
def define_model_callbacks: (*untyped callbacks) -> untyped
|
915
|
+
|
916
|
+
def _define_before_model_callback: (untyped klass, untyped callback) -> untyped
|
917
|
+
|
918
|
+
def _define_around_model_callback: (untyped klass, untyped callback) -> untyped
|
919
|
+
|
920
|
+
def _define_after_model_callback: (untyped klass, untyped callback) -> untyped
|
921
|
+
end
|
922
|
+
|
923
|
+
# == Active \Model \Conversion
|
924
|
+
#
|
925
|
+
# Handles default conversions: to_model, to_key, to_param, and to_partial_path.
|
926
|
+
#
|
927
|
+
# Let's take for example this non-persisted object.
|
928
|
+
#
|
929
|
+
# class ContactMessage
|
930
|
+
# include ActiveModel::Conversion
|
931
|
+
#
|
932
|
+
# # ContactMessage are never persisted in the DB
|
933
|
+
# def persisted?
|
934
|
+
# false
|
935
|
+
# end
|
936
|
+
# end
|
937
|
+
#
|
938
|
+
# cm = ContactMessage.new
|
939
|
+
# cm.to_model == cm # => true
|
940
|
+
# cm.to_key # => nil
|
941
|
+
# cm.to_param # => nil
|
942
|
+
# cm.to_partial_path # => "contact_messages/contact_message"
|
943
|
+
module ActiveModel::Conversion
|
944
|
+
extend ActiveSupport::Concern
|
945
|
+
|
946
|
+
# If your object is already designed to implement all of the \Active \Model
|
947
|
+
# you can use the default <tt>:to_model</tt> implementation, which simply
|
948
|
+
# returns +self+.
|
949
|
+
#
|
950
|
+
# class Person
|
951
|
+
# include ActiveModel::Conversion
|
952
|
+
# end
|
953
|
+
#
|
954
|
+
# person = Person.new
|
955
|
+
# person.to_model == person # => true
|
956
|
+
#
|
957
|
+
# If your model does not act like an \Active \Model object, then you should
|
958
|
+
# define <tt>:to_model</tt> yourself returning a proxy object that wraps
|
959
|
+
# your object with \Active \Model compliant methods.
|
960
|
+
def to_model: () -> untyped
|
961
|
+
|
962
|
+
# Returns an Array of all key attributes if any of the attributes is set, whether or not
|
963
|
+
# the object is persisted. Returns +nil+ if there are no key attributes.
|
964
|
+
#
|
965
|
+
# class Person
|
966
|
+
# include ActiveModel::Conversion
|
967
|
+
# attr_accessor :id
|
968
|
+
#
|
969
|
+
# def initialize(id)
|
970
|
+
# @id = id
|
971
|
+
# end
|
972
|
+
# end
|
973
|
+
#
|
974
|
+
# person = Person.new(1)
|
975
|
+
# person.to_key # => [1]
|
976
|
+
def to_key: () -> untyped
|
977
|
+
|
978
|
+
# Returns a +string+ representing the object's key suitable for use in URLs,
|
979
|
+
# or +nil+ if <tt>persisted?</tt> is +false+.
|
980
|
+
#
|
981
|
+
# class Person
|
982
|
+
# include ActiveModel::Conversion
|
983
|
+
# attr_accessor :id
|
984
|
+
#
|
985
|
+
# def initialize(id)
|
986
|
+
# @id = id
|
987
|
+
# end
|
988
|
+
#
|
989
|
+
# def persisted?
|
990
|
+
# true
|
991
|
+
# end
|
992
|
+
# end
|
993
|
+
#
|
994
|
+
# person = Person.new(1)
|
995
|
+
# person.to_param # => "1"
|
996
|
+
def to_param: () -> untyped
|
997
|
+
|
998
|
+
# Returns a +string+ identifying the path associated with the object.
|
999
|
+
# ActionPack uses this to find a suitable partial to represent the object.
|
1000
|
+
#
|
1001
|
+
# class Person
|
1002
|
+
# include ActiveModel::Conversion
|
1003
|
+
# end
|
1004
|
+
#
|
1005
|
+
# person = Person.new
|
1006
|
+
# person.to_partial_path # => "people/person"
|
1007
|
+
def to_partial_path: () -> untyped
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
module ActiveModel::Conversion::ClassMethods
|
1011
|
+
def _to_partial_path: () -> untyped
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
# == Active \Model \Dirty
|
1015
|
+
#
|
1016
|
+
# Provides a way to track changes in your object in the same way as
|
1017
|
+
# Active Record does.
|
1018
|
+
#
|
1019
|
+
# The requirements for implementing ActiveModel::Dirty are:
|
1020
|
+
#
|
1021
|
+
# * <tt>include ActiveModel::Dirty</tt> in your object.
|
1022
|
+
# * Call <tt>define_attribute_methods</tt> passing each method you want to
|
1023
|
+
# track.
|
1024
|
+
# * Call <tt>[attr_name]_will_change!</tt> before each change to the tracked
|
1025
|
+
# attribute.
|
1026
|
+
# * Call <tt>changes_applied</tt> after the changes are persisted.
|
1027
|
+
# * Call <tt>clear_changes_information</tt> when you want to reset the changes
|
1028
|
+
# information.
|
1029
|
+
# * Call <tt>restore_attributes</tt> when you want to restore previous data.
|
1030
|
+
#
|
1031
|
+
# A minimal implementation could be:
|
1032
|
+
#
|
1033
|
+
# class Person
|
1034
|
+
# include ActiveModel::Dirty
|
1035
|
+
#
|
1036
|
+
# define_attribute_methods :name
|
1037
|
+
#
|
1038
|
+
# def initialize
|
1039
|
+
# @name = nil
|
1040
|
+
# end
|
1041
|
+
#
|
1042
|
+
# def name
|
1043
|
+
# @name
|
1044
|
+
# end
|
1045
|
+
#
|
1046
|
+
# def name=(val)
|
1047
|
+
# name_will_change! unless val == @name
|
1048
|
+
# @name = val
|
1049
|
+
# end
|
1050
|
+
#
|
1051
|
+
# def save
|
1052
|
+
# # do persistence work
|
1053
|
+
#
|
1054
|
+
# changes_applied
|
1055
|
+
# end
|
1056
|
+
#
|
1057
|
+
# def reload!
|
1058
|
+
# # get the values from the persistence layer
|
1059
|
+
#
|
1060
|
+
# clear_changes_information
|
1061
|
+
# end
|
1062
|
+
#
|
1063
|
+
# def rollback!
|
1064
|
+
# restore_attributes
|
1065
|
+
# end
|
1066
|
+
# end
|
1067
|
+
#
|
1068
|
+
# A newly instantiated +Person+ object is unchanged:
|
1069
|
+
#
|
1070
|
+
# person = Person.new
|
1071
|
+
# person.changed? # => false
|
1072
|
+
#
|
1073
|
+
# Change the name:
|
1074
|
+
#
|
1075
|
+
# person.name = 'Bob'
|
1076
|
+
# person.changed? # => true
|
1077
|
+
# person.name_changed? # => true
|
1078
|
+
# person.name_changed?(from: nil, to: "Bob") # => true
|
1079
|
+
# person.name_was # => nil
|
1080
|
+
# person.name_change # => [nil, "Bob"]
|
1081
|
+
# person.name = 'Bill'
|
1082
|
+
# person.name_change # => [nil, "Bill"]
|
1083
|
+
#
|
1084
|
+
# Save the changes:
|
1085
|
+
#
|
1086
|
+
# person.save
|
1087
|
+
# person.changed? # => false
|
1088
|
+
# person.name_changed? # => false
|
1089
|
+
#
|
1090
|
+
# Reset the changes:
|
1091
|
+
#
|
1092
|
+
# person.previous_changes # => {"name" => [nil, "Bill"]}
|
1093
|
+
# person.name_previously_changed? # => true
|
1094
|
+
# person.name_previous_change # => [nil, "Bill"]
|
1095
|
+
# person.reload!
|
1096
|
+
# person.previous_changes # => {}
|
1097
|
+
#
|
1098
|
+
# Rollback the changes:
|
1099
|
+
#
|
1100
|
+
# person.name = "Uncle Bob"
|
1101
|
+
# person.rollback!
|
1102
|
+
# person.name # => "Bill"
|
1103
|
+
# person.name_changed? # => false
|
1104
|
+
#
|
1105
|
+
# Assigning the same value leaves the attribute unchanged:
|
1106
|
+
#
|
1107
|
+
# person.name = 'Bill'
|
1108
|
+
# person.name_changed? # => false
|
1109
|
+
# person.name_change # => nil
|
1110
|
+
#
|
1111
|
+
# Which attributes have changed?
|
1112
|
+
#
|
1113
|
+
# person.name = 'Bob'
|
1114
|
+
# person.changed # => ["name"]
|
1115
|
+
# person.changes # => {"name" => ["Bill", "Bob"]}
|
1116
|
+
#
|
1117
|
+
# If an attribute is modified in-place then make use of
|
1118
|
+
# <tt>[attribute_name]_will_change!</tt> to mark that the attribute is changing.
|
1119
|
+
# Otherwise \Active \Model can't track changes to in-place attributes. Note
|
1120
|
+
# that Active Record can detect in-place modifications automatically. You do
|
1121
|
+
# not need to call <tt>[attribute_name]_will_change!</tt> on Active Record models.
|
1122
|
+
#
|
1123
|
+
# person.name_will_change!
|
1124
|
+
# person.name_change # => ["Bill", "Bill"]
|
1125
|
+
# person.name << 'y'
|
1126
|
+
# person.name_change # => ["Bill", "Billy"]
|
1127
|
+
module ActiveModel::Dirty
|
1128
|
+
extend ActiveSupport::Concern
|
1129
|
+
|
1130
|
+
include ActiveModel::AttributeMethods
|
1131
|
+
|
1132
|
+
def initialize_dup: (untyped other) -> untyped
|
1133
|
+
|
1134
|
+
# Clears dirty data and moves +changes+ to +previously_changed+ and
|
1135
|
+
# +mutations_from_database+ to +mutations_before_last_save+ respectively.
|
1136
|
+
def changes_applied: () -> untyped
|
1137
|
+
|
1138
|
+
# Returns +true+ if any of the attributes has unsaved changes, +false+ otherwise.
|
1139
|
+
#
|
1140
|
+
# person.changed? # => false
|
1141
|
+
# person.name = 'bob'
|
1142
|
+
# person.changed? # => true
|
1143
|
+
def changed?: () -> untyped
|
1144
|
+
|
1145
|
+
# Returns an array with the name of the attributes with unsaved changes.
|
1146
|
+
#
|
1147
|
+
# person.changed # => []
|
1148
|
+
# person.name = 'bob'
|
1149
|
+
# person.changed # => ["name"]
|
1150
|
+
def changed: () -> untyped
|
1151
|
+
|
1152
|
+
def attribute_changed?: (untyped attr_name, **untyped options) -> untyped
|
1153
|
+
|
1154
|
+
def attribute_was: (untyped attr_name) -> untyped
|
1155
|
+
|
1156
|
+
def attribute_previously_changed?: (untyped attr_name) -> untyped
|
1157
|
+
|
1158
|
+
# Restore all previous data of the provided attributes.
|
1159
|
+
def restore_attributes: (?untyped attr_names) -> untyped
|
1160
|
+
|
1161
|
+
# Clears all dirty data: current changes and previous changes.
|
1162
|
+
def clear_changes_information: () -> untyped
|
1163
|
+
|
1164
|
+
def clear_attribute_changes: (untyped attr_names) -> untyped
|
1165
|
+
|
1166
|
+
# Returns a hash of the attributes with unsaved changes indicating their original
|
1167
|
+
# values like <tt>attr => original value</tt>.
|
1168
|
+
#
|
1169
|
+
# person.name # => "bob"
|
1170
|
+
# person.name = 'robert'
|
1171
|
+
# person.changed_attributes # => {"name" => "bob"}
|
1172
|
+
def changed_attributes: () -> untyped
|
1173
|
+
|
1174
|
+
# Returns a hash of changed attributes indicating their original
|
1175
|
+
# and new values like <tt>attr => [original value, new value]</tt>.
|
1176
|
+
#
|
1177
|
+
# person.changes # => {}
|
1178
|
+
# person.name = 'bob'
|
1179
|
+
# person.changes # => { "name" => ["bill", "bob"] }
|
1180
|
+
def changes: () -> untyped
|
1181
|
+
|
1182
|
+
# Returns a hash of attributes that were changed before the model was saved.
|
1183
|
+
#
|
1184
|
+
# person.name # => "bob"
|
1185
|
+
# person.name = 'robert'
|
1186
|
+
# person.save
|
1187
|
+
# person.previous_changes # => {"name" => ["bob", "robert"]}
|
1188
|
+
def previous_changes: () -> untyped
|
1189
|
+
|
1190
|
+
def attribute_changed_in_place?: (untyped attr_name) -> untyped
|
1191
|
+
|
1192
|
+
def clear_attribute_change: (untyped attr_name) -> untyped
|
1193
|
+
|
1194
|
+
def mutations_from_database: () -> untyped
|
1195
|
+
|
1196
|
+
def forget_attribute_assignments: () -> untyped
|
1197
|
+
|
1198
|
+
def mutations_before_last_save: () -> untyped
|
1199
|
+
|
1200
|
+
# Dispatch target for <tt>*_change</tt> attribute methods.
|
1201
|
+
def attribute_change: (untyped attr_name) -> untyped
|
1202
|
+
|
1203
|
+
# Dispatch target for <tt>*_previous_change</tt> attribute methods.
|
1204
|
+
def attribute_previous_change: (untyped attr_name) -> untyped
|
1205
|
+
|
1206
|
+
# Dispatch target for <tt>*_will_change!</tt> attribute methods.
|
1207
|
+
def attribute_will_change!: (untyped attr_name) -> untyped
|
1208
|
+
|
1209
|
+
# Dispatch target for <tt>restore_*!</tt> attribute methods.
|
1210
|
+
def restore_attribute!: (untyped attr_name) -> untyped
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
# == Active \Model \Errors
|
1214
|
+
#
|
1215
|
+
# Provides a modified +Hash+ that you can include in your object
|
1216
|
+
# for handling error messages and interacting with Action View helpers.
|
1217
|
+
#
|
1218
|
+
# A minimal implementation could be:
|
1219
|
+
#
|
1220
|
+
# class Person
|
1221
|
+
# # Required dependency for ActiveModel::Errors
|
1222
|
+
# extend ActiveModel::Naming
|
1223
|
+
#
|
1224
|
+
# def initialize
|
1225
|
+
# @errors = ActiveModel::Errors.new(self)
|
1226
|
+
# end
|
1227
|
+
#
|
1228
|
+
# attr_accessor :name
|
1229
|
+
# attr_reader :errors
|
1230
|
+
#
|
1231
|
+
# def validate!
|
1232
|
+
# errors.add(:name, :blank, message: "cannot be nil") if name.nil?
|
1233
|
+
# end
|
1234
|
+
#
|
1235
|
+
# # The following methods are needed to be minimally implemented
|
1236
|
+
#
|
1237
|
+
# def read_attribute_for_validation(attr)
|
1238
|
+
# send(attr)
|
1239
|
+
# end
|
1240
|
+
#
|
1241
|
+
# def self.human_attribute_name(attr, options = {})
|
1242
|
+
# attr
|
1243
|
+
# end
|
1244
|
+
#
|
1245
|
+
# def self.lookup_ancestors
|
1246
|
+
# [self]
|
1247
|
+
# end
|
1248
|
+
# end
|
1249
|
+
#
|
1250
|
+
# The last three methods are required in your object for +Errors+ to be
|
1251
|
+
# able to generate error messages correctly and also handle multiple
|
1252
|
+
# languages. Of course, if you extend your object with <tt>ActiveModel::Translation</tt>
|
1253
|
+
# you will not need to implement the last two. Likewise, using
|
1254
|
+
# <tt>ActiveModel::Validations</tt> will handle the validation related methods
|
1255
|
+
# for you.
|
1256
|
+
#
|
1257
|
+
# The above allows you to do:
|
1258
|
+
#
|
1259
|
+
# person = Person.new
|
1260
|
+
# person.validate! # => ["cannot be nil"]
|
1261
|
+
# person.errors.full_messages # => ["name cannot be nil"]
|
1262
|
+
# # etc..
|
1263
|
+
class ActiveModel::Errors
|
1264
|
+
include Enumerable[untyped, untyped]
|
1265
|
+
|
1266
|
+
attr_accessor i18n_customize_full_message: untyped
|
1267
|
+
|
1268
|
+
attr_reader messages: untyped
|
1269
|
+
|
1270
|
+
attr_reader details: untyped
|
1271
|
+
|
1272
|
+
# Pass in the instance of the object that is using the errors object.
|
1273
|
+
#
|
1274
|
+
# class Person
|
1275
|
+
# def initialize
|
1276
|
+
# @errors = ActiveModel::Errors.new(self)
|
1277
|
+
# end
|
1278
|
+
# end
|
1279
|
+
def initialize: (untyped base) -> untyped
|
1280
|
+
|
1281
|
+
def initialize_dup: (untyped other) -> untyped
|
1282
|
+
|
1283
|
+
def copy!: (untyped other) -> untyped
|
1284
|
+
|
1285
|
+
# Merges the errors from <tt>other</tt>.
|
1286
|
+
#
|
1287
|
+
# other - The ActiveModel::Errors instance.
|
1288
|
+
#
|
1289
|
+
# Examples
|
1290
|
+
#
|
1291
|
+
# person.errors.merge!(other)
|
1292
|
+
def merge!: (untyped other) -> untyped
|
1293
|
+
|
1294
|
+
# Removes all errors except the given keys. Returns a hash containing the removed errors.
|
1295
|
+
#
|
1296
|
+
# person.errors.keys # => [:name, :age, :gender, :city]
|
1297
|
+
# person.errors.slice!(:age, :gender) # => { :name=>["cannot be nil"], :city=>["cannot be nil"] }
|
1298
|
+
# person.errors.keys # => [:age, :gender]
|
1299
|
+
def slice!: (*untyped keys) -> untyped
|
1300
|
+
|
1301
|
+
# Clear the error messages.
|
1302
|
+
#
|
1303
|
+
# person.errors.full_messages # => ["name cannot be nil"]
|
1304
|
+
# person.errors.clear
|
1305
|
+
# person.errors.full_messages # => []
|
1306
|
+
def clear: () -> untyped
|
1307
|
+
|
1308
|
+
# Returns +true+ if the error messages include an error for the given key
|
1309
|
+
# +attribute+, +false+ otherwise.
|
1310
|
+
#
|
1311
|
+
# person.errors.messages # => {:name=>["cannot be nil"]}
|
1312
|
+
# person.errors.include?(:name) # => true
|
1313
|
+
# person.errors.include?(:age) # => false
|
1314
|
+
def include?: (untyped attribute) -> untyped
|
1315
|
+
|
1316
|
+
# Delete messages for +key+. Returns the deleted messages.
|
1317
|
+
#
|
1318
|
+
# person.errors[:name] # => ["cannot be nil"]
|
1319
|
+
# person.errors.delete(:name) # => ["cannot be nil"]
|
1320
|
+
# person.errors[:name] # => []
|
1321
|
+
def delete: (untyped key) -> untyped
|
1322
|
+
|
1323
|
+
# When passed a symbol or a name of a method, returns an array of errors
|
1324
|
+
# for the method.
|
1325
|
+
#
|
1326
|
+
# person.errors[:name] # => ["cannot be nil"]
|
1327
|
+
# person.errors['name'] # => ["cannot be nil"]
|
1328
|
+
def []: (untyped attribute) -> untyped
|
1329
|
+
|
1330
|
+
# Iterates through each error key, value pair in the error messages hash.
|
1331
|
+
# Yields the attribute and the error for that attribute. If the attribute
|
1332
|
+
# has more than one error message, yields once for each error message.
|
1333
|
+
#
|
1334
|
+
# person.errors.add(:name, :blank, message: "can't be blank")
|
1335
|
+
# person.errors.each do |attribute, error|
|
1336
|
+
# # Will yield :name and "can't be blank"
|
1337
|
+
# end
|
1338
|
+
#
|
1339
|
+
# person.errors.add(:name, :not_specified, message: "must be specified")
|
1340
|
+
# person.errors.each do |attribute, error|
|
1341
|
+
# # Will yield :name and "can't be blank"
|
1342
|
+
# # then yield :name and "must be specified"
|
1343
|
+
# end
|
1344
|
+
def each: () { (untyped, untyped) -> untyped } -> untyped
|
1345
|
+
|
1346
|
+
# Returns the number of error messages.
|
1347
|
+
#
|
1348
|
+
# person.errors.add(:name, :blank, message: "can't be blank")
|
1349
|
+
# person.errors.size # => 1
|
1350
|
+
# person.errors.add(:name, :not_specified, message: "must be specified")
|
1351
|
+
# person.errors.size # => 2
|
1352
|
+
def size: () -> untyped
|
1353
|
+
|
1354
|
+
# Returns all message values.
|
1355
|
+
#
|
1356
|
+
# person.errors.messages # => {:name=>["cannot be nil", "must be specified"]}
|
1357
|
+
# person.errors.values # => [["cannot be nil", "must be specified"]]
|
1358
|
+
def values: () -> untyped
|
1359
|
+
|
1360
|
+
# Returns all message keys.
|
1361
|
+
#
|
1362
|
+
# person.errors.messages # => {:name=>["cannot be nil", "must be specified"]}
|
1363
|
+
# person.errors.keys # => [:name]
|
1364
|
+
def keys: () -> untyped
|
1365
|
+
|
1366
|
+
# Returns +true+ if no errors are found, +false+ otherwise.
|
1367
|
+
# If the error message is a string it can be empty.
|
1368
|
+
#
|
1369
|
+
# person.errors.full_messages # => ["name cannot be nil"]
|
1370
|
+
# person.errors.empty? # => false
|
1371
|
+
def empty?: () -> untyped
|
1372
|
+
|
1373
|
+
# Returns an xml formatted representation of the Errors hash.
|
1374
|
+
#
|
1375
|
+
# person.errors.add(:name, :blank, message: "can't be blank")
|
1376
|
+
# person.errors.add(:name, :not_specified, message: "must be specified")
|
1377
|
+
# person.errors.to_xml
|
1378
|
+
# # =>
|
1379
|
+
# # <?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
1380
|
+
# # <errors>
|
1381
|
+
# # <error>name can't be blank</error>
|
1382
|
+
# # <error>name must be specified</error>
|
1383
|
+
# # </errors>
|
1384
|
+
def to_xml: (?::Hash[untyped, untyped] options) -> untyped
|
1385
|
+
|
1386
|
+
# Returns a Hash that can be used as the JSON representation for this
|
1387
|
+
# object. You can pass the <tt>:full_messages</tt> option. This determines
|
1388
|
+
# if the json object should contain full messages or not (false by default).
|
1389
|
+
#
|
1390
|
+
# person.errors.as_json # => {:name=>["cannot be nil"]}
|
1391
|
+
# person.errors.as_json(full_messages: true) # => {:name=>["name cannot be nil"]}
|
1392
|
+
def as_json: (?untyped? options) -> untyped
|
1393
|
+
|
1394
|
+
# Returns a Hash of attributes with their error messages. If +full_messages+
|
1395
|
+
# is +true+, it will contain full messages (see +full_message+).
|
1396
|
+
#
|
1397
|
+
# person.errors.to_hash # => {:name=>["cannot be nil"]}
|
1398
|
+
# person.errors.to_hash(true) # => {:name=>["name cannot be nil"]}
|
1399
|
+
def to_hash: (?bool full_messages) -> untyped
|
1400
|
+
|
1401
|
+
# Adds +message+ to the error messages and used validator type to +details+ on +attribute+.
|
1402
|
+
# More than one error can be added to the same +attribute+.
|
1403
|
+
# If no +message+ is supplied, <tt>:invalid</tt> is assumed.
|
1404
|
+
#
|
1405
|
+
# person.errors.add(:name)
|
1406
|
+
# # => ["is invalid"]
|
1407
|
+
# person.errors.add(:name, :not_implemented, message: "must be implemented")
|
1408
|
+
# # => ["is invalid", "must be implemented"]
|
1409
|
+
#
|
1410
|
+
# person.errors.messages
|
1411
|
+
# # => {:name=>["is invalid", "must be implemented"]}
|
1412
|
+
#
|
1413
|
+
# person.errors.details
|
1414
|
+
# # => {:name=>[{error: :not_implemented}, {error: :invalid}]}
|
1415
|
+
#
|
1416
|
+
# If +message+ is a symbol, it will be translated using the appropriate
|
1417
|
+
# scope (see +generate_message+).
|
1418
|
+
#
|
1419
|
+
# If +message+ is a proc, it will be called, allowing for things like
|
1420
|
+
# <tt>Time.now</tt> to be used within an error.
|
1421
|
+
#
|
1422
|
+
# If the <tt>:strict</tt> option is set to +true+, it will raise
|
1423
|
+
# ActiveModel::StrictValidationFailed instead of adding the error.
|
1424
|
+
# <tt>:strict</tt> option can also be set to any other exception.
|
1425
|
+
#
|
1426
|
+
# person.errors.add(:name, :invalid, strict: true)
|
1427
|
+
# # => ActiveModel::StrictValidationFailed: Name is invalid
|
1428
|
+
# person.errors.add(:name, :invalid, strict: NameIsInvalid)
|
1429
|
+
# # => NameIsInvalid: Name is invalid
|
1430
|
+
#
|
1431
|
+
# person.errors.messages # => {}
|
1432
|
+
#
|
1433
|
+
# +attribute+ should be set to <tt>:base</tt> if the error is not
|
1434
|
+
# directly associated with a single attribute.
|
1435
|
+
#
|
1436
|
+
# person.errors.add(:base, :name_or_email_blank,
|
1437
|
+
# message: "either name or email must be present")
|
1438
|
+
# person.errors.messages
|
1439
|
+
# # => {:base=>["either name or email must be present"]}
|
1440
|
+
# person.errors.details
|
1441
|
+
# # => {:base=>[{error: :name_or_email_blank}]}
|
1442
|
+
def add: (untyped attribute, ?::Symbol message, ?::Hash[untyped, untyped] options) -> untyped
|
1443
|
+
|
1444
|
+
# Returns +true+ if an error on the attribute with the given message is
|
1445
|
+
# present, or +false+ otherwise. +message+ is treated the same as for +add+.
|
1446
|
+
#
|
1447
|
+
# person.errors.add :name, :blank
|
1448
|
+
# person.errors.added? :name, :blank # => true
|
1449
|
+
# person.errors.added? :name, "can't be blank" # => true
|
1450
|
+
#
|
1451
|
+
# If the error message requires options, then it returns +true+ with
|
1452
|
+
# the correct options, or +false+ with incorrect or missing options.
|
1453
|
+
#
|
1454
|
+
# person.errors.add :name, :too_long, { count: 25 }
|
1455
|
+
# person.errors.added? :name, :too_long, count: 25 # => true
|
1456
|
+
# person.errors.added? :name, "is too long (maximum is 25 characters)" # => true
|
1457
|
+
# person.errors.added? :name, :too_long, count: 24 # => false
|
1458
|
+
# person.errors.added? :name, :too_long # => false
|
1459
|
+
# person.errors.added? :name, "is too long" # => false
|
1460
|
+
def added?: (untyped attribute, ?::Symbol message, ?::Hash[untyped, untyped] options) -> untyped
|
1461
|
+
|
1462
|
+
# Returns +true+ if an error on the attribute with the given message is
|
1463
|
+
# present, or +false+ otherwise. +message+ is treated the same as for +add+.
|
1464
|
+
#
|
1465
|
+
# person.errors.add :age
|
1466
|
+
# person.errors.add :name, :too_long, { count: 25 }
|
1467
|
+
# person.errors.of_kind? :age # => true
|
1468
|
+
# person.errors.of_kind? :name # => false
|
1469
|
+
# person.errors.of_kind? :name, :too_long # => true
|
1470
|
+
# person.errors.of_kind? :name, "is too long (maximum is 25 characters)" # => true
|
1471
|
+
# person.errors.of_kind? :name, :not_too_long # => false
|
1472
|
+
# person.errors.of_kind? :name, "is too long" # => false
|
1473
|
+
def of_kind?: (untyped attribute, ?::Symbol message) -> untyped
|
1474
|
+
|
1475
|
+
# Returns all the full error messages in an array.
|
1476
|
+
#
|
1477
|
+
# class Person
|
1478
|
+
# validates_presence_of :name, :address, :email
|
1479
|
+
# validates_length_of :name, in: 5..30
|
1480
|
+
# end
|
1481
|
+
#
|
1482
|
+
# person = Person.create(address: '123 First St.')
|
1483
|
+
# person.errors.full_messages
|
1484
|
+
# # => ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Email can't be blank"]
|
1485
|
+
def full_messages: () -> untyped
|
1486
|
+
|
1487
|
+
# Returns all the full error messages for a given attribute in an array.
|
1488
|
+
#
|
1489
|
+
# class Person
|
1490
|
+
# validates_presence_of :name, :email
|
1491
|
+
# validates_length_of :name, in: 5..30
|
1492
|
+
# end
|
1493
|
+
#
|
1494
|
+
# person = Person.create()
|
1495
|
+
# person.errors.full_messages_for(:name)
|
1496
|
+
# # => ["Name is too short (minimum is 5 characters)", "Name can't be blank"]
|
1497
|
+
def full_messages_for: (untyped attribute) -> untyped
|
1498
|
+
|
1499
|
+
# Returns a full message for a given attribute.
|
1500
|
+
#
|
1501
|
+
# person.errors.full_message(:name, 'is invalid') # => "Name is invalid"
|
1502
|
+
#
|
1503
|
+
# The `"%{attribute} %{message}"` error format can be overridden with either
|
1504
|
+
#
|
1505
|
+
# * <tt>activemodel.errors.models.person/contacts/addresses.attributes.street.format</tt>
|
1506
|
+
# * <tt>activemodel.errors.models.person/contacts/addresses.format</tt>
|
1507
|
+
# * <tt>activemodel.errors.models.person.attributes.name.format</tt>
|
1508
|
+
# * <tt>activemodel.errors.models.person.format</tt>
|
1509
|
+
# * <tt>errors.format</tt>
|
1510
|
+
def full_message: (untyped attribute, untyped message) -> untyped
|
1511
|
+
|
1512
|
+
# Translates an error message in its default scope
|
1513
|
+
# (<tt>activemodel.errors.messages</tt>).
|
1514
|
+
#
|
1515
|
+
# Error messages are first looked up in <tt>activemodel.errors.models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>,
|
1516
|
+
# if it's not there, it's looked up in <tt>activemodel.errors.models.MODEL.MESSAGE</tt> and if
|
1517
|
+
# that is not there also, it returns the translation of the default message
|
1518
|
+
# (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model
|
1519
|
+
# name, translated attribute name and the value are available for
|
1520
|
+
# interpolation.
|
1521
|
+
#
|
1522
|
+
# When using inheritance in your models, it will check all the inherited
|
1523
|
+
# models too, but only if the model itself hasn't been found. Say you have
|
1524
|
+
# <tt>class Admin < User; end</tt> and you wanted the translation for
|
1525
|
+
# the <tt>:blank</tt> error message for the <tt>title</tt> attribute,
|
1526
|
+
# it looks for these translations:
|
1527
|
+
#
|
1528
|
+
# * <tt>activemodel.errors.models.admin.attributes.title.blank</tt>
|
1529
|
+
# * <tt>activemodel.errors.models.admin.blank</tt>
|
1530
|
+
# * <tt>activemodel.errors.models.user.attributes.title.blank</tt>
|
1531
|
+
# * <tt>activemodel.errors.models.user.blank</tt>
|
1532
|
+
# * any default you provided through the +options+ hash (in the <tt>activemodel.errors</tt> scope)
|
1533
|
+
# * <tt>activemodel.errors.messages.blank</tt>
|
1534
|
+
# * <tt>errors.attributes.title.blank</tt>
|
1535
|
+
# * <tt>errors.messages.blank</tt>
|
1536
|
+
def generate_message: (untyped attribute, ?::Symbol `type`, ?::Hash[untyped, untyped] options) -> untyped
|
1537
|
+
|
1538
|
+
def marshal_dump: () -> ::Array[untyped]
|
1539
|
+
|
1540
|
+
def marshal_load: (untyped array) -> untyped
|
1541
|
+
|
1542
|
+
def init_with: (untyped coder) -> untyped
|
1543
|
+
|
1544
|
+
def normalize_message: (untyped attribute, untyped message, untyped options) -> untyped
|
1545
|
+
|
1546
|
+
def normalize_detail: (untyped message, untyped options) -> untyped
|
1547
|
+
|
1548
|
+
def without_default_proc: (untyped hash) -> untyped
|
1549
|
+
|
1550
|
+
def apply_default_array: (untyped hash) -> untyped
|
1551
|
+
end
|
1552
|
+
|
1553
|
+
ActiveModel::Errors::CALLBACKS_OPTIONS: ::Array[untyped]
|
1554
|
+
|
1555
|
+
ActiveModel::Errors::MESSAGE_OPTIONS: ::Array[untyped]
|
1556
|
+
|
1557
|
+
# Raised when a validation cannot be corrected by end users and are considered
|
1558
|
+
# exceptional.
|
1559
|
+
#
|
1560
|
+
# class Person
|
1561
|
+
# include ActiveModel::Validations
|
1562
|
+
#
|
1563
|
+
# attr_accessor :name
|
1564
|
+
#
|
1565
|
+
# validates_presence_of :name, strict: true
|
1566
|
+
# end
|
1567
|
+
#
|
1568
|
+
# person = Person.new
|
1569
|
+
# person.name = nil
|
1570
|
+
# person.valid?
|
1571
|
+
# # => ActiveModel::StrictValidationFailed: Name can't be blank
|
1572
|
+
class ActiveModel::StrictValidationFailed < StandardError
|
1573
|
+
end
|
1574
|
+
|
1575
|
+
# Raised when attribute values are out of range.
|
1576
|
+
class ActiveModel::RangeError < ::RangeError
|
1577
|
+
end
|
1578
|
+
|
1579
|
+
# Raised when unknown attributes are supplied via mass assignment.
|
1580
|
+
#
|
1581
|
+
# class Person
|
1582
|
+
# include ActiveModel::AttributeAssignment
|
1583
|
+
# include ActiveModel::Validations
|
1584
|
+
# end
|
1585
|
+
#
|
1586
|
+
# person = Person.new
|
1587
|
+
# person.assign_attributes(name: 'Gorby')
|
1588
|
+
# # => ActiveModel::UnknownAttributeError: unknown attribute 'name' for Person.
|
1589
|
+
class ActiveModel::UnknownAttributeError[T] < NoMethodError[T]
|
1590
|
+
attr_reader record: untyped
|
1591
|
+
|
1592
|
+
attr_reader attribute: untyped
|
1593
|
+
|
1594
|
+
def initialize: (untyped record, untyped attribute) -> untyped
|
1595
|
+
end
|
1596
|
+
|
1597
|
+
# Raised when forbidden attributes are used for mass assignment.
|
1598
|
+
#
|
1599
|
+
# class Person < ActiveRecord::Base
|
1600
|
+
# end
|
1601
|
+
#
|
1602
|
+
# params = ActionController::Parameters.new(name: 'Bob')
|
1603
|
+
# Person.new(params)
|
1604
|
+
# # => ActiveModel::ForbiddenAttributesError
|
1605
|
+
#
|
1606
|
+
# params.permit!
|
1607
|
+
# Person.new(params)
|
1608
|
+
# # => #<Person id: nil, name: "Bob">
|
1609
|
+
class ActiveModel::ForbiddenAttributesError < StandardError
|
1610
|
+
end
|
1611
|
+
|
1612
|
+
module ActiveModel::ForbiddenAttributesProtection
|
1613
|
+
def sanitize_for_mass_assignment: (untyped attributes) -> untyped
|
1614
|
+
end
|
1615
|
+
|
1616
|
+
module ActiveModel::VERSION
|
1617
|
+
end
|
1618
|
+
|
1619
|
+
ActiveModel::VERSION::MAJOR: ::Integer
|
1620
|
+
|
1621
|
+
ActiveModel::VERSION::MINOR: ::Integer
|
1622
|
+
|
1623
|
+
ActiveModel::VERSION::TINY: ::Integer
|
1624
|
+
|
1625
|
+
ActiveModel::VERSION::PRE: ::String
|
1626
|
+
|
1627
|
+
ActiveModel::VERSION::STRING: untyped
|
1628
|
+
|
1629
|
+
module ActiveModel::Lint
|
1630
|
+
end
|
1631
|
+
|
1632
|
+
# == Active \Model \Lint \Tests
|
1633
|
+
#
|
1634
|
+
# You can test whether an object is compliant with the Active \Model API by
|
1635
|
+
# including <tt>ActiveModel::Lint::Tests</tt> in your TestCase. It will
|
1636
|
+
# include tests that tell you whether your object is fully compliant,
|
1637
|
+
# or if not, which aspects of the API are not implemented.
|
1638
|
+
#
|
1639
|
+
# Note an object is not required to implement all APIs in order to work
|
1640
|
+
# with Action Pack. This module only intends to provide guidance in case
|
1641
|
+
# you want all features out of the box.
|
1642
|
+
#
|
1643
|
+
# These tests do not attempt to determine the semantic correctness of the
|
1644
|
+
# returned values. For instance, you could implement <tt>valid?</tt> to
|
1645
|
+
# always return +true+, and the tests would pass. It is up to you to ensure
|
1646
|
+
# that the values are semantically meaningful.
|
1647
|
+
#
|
1648
|
+
# Objects you pass in are expected to return a compliant object from a call
|
1649
|
+
# to <tt>to_model</tt>. It is perfectly fine for <tt>to_model</tt> to return
|
1650
|
+
# +self+.
|
1651
|
+
module ActiveModel::Lint::Tests
|
1652
|
+
# Passes if the object's model responds to <tt>to_key</tt> and if calling
|
1653
|
+
# this method returns +nil+ when the object is not persisted.
|
1654
|
+
# Fails otherwise.
|
1655
|
+
#
|
1656
|
+
# <tt>to_key</tt> returns an Enumerable of all (primary) key attributes
|
1657
|
+
# of the model, and is used to a generate unique DOM id for the object.
|
1658
|
+
def test_to_key: () -> untyped
|
1659
|
+
|
1660
|
+
# Passes if the object's model responds to <tt>to_param</tt> and if
|
1661
|
+
# calling this method returns +nil+ when the object is not persisted.
|
1662
|
+
# Fails otherwise.
|
1663
|
+
#
|
1664
|
+
# <tt>to_param</tt> is used to represent the object's key in URLs.
|
1665
|
+
# Implementers can decide to either raise an exception or provide a
|
1666
|
+
# default in case the record uses a composite primary key. There are no
|
1667
|
+
# tests for this behavior in lint because it doesn't make sense to force
|
1668
|
+
# any of the possible implementation strategies on the implementer.
|
1669
|
+
def test_to_param: () -> untyped
|
1670
|
+
|
1671
|
+
# Passes if the object's model responds to <tt>to_partial_path</tt> and if
|
1672
|
+
# calling this method returns a string. Fails otherwise.
|
1673
|
+
#
|
1674
|
+
# <tt>to_partial_path</tt> is used for looking up partials. For example,
|
1675
|
+
# a BlogPost model might return "blog_posts/blog_post".
|
1676
|
+
def test_to_partial_path: () -> untyped
|
1677
|
+
|
1678
|
+
# Passes if the object's model responds to <tt>persisted?</tt> and if
|
1679
|
+
# calling this method returns either +true+ or +false+. Fails otherwise.
|
1680
|
+
#
|
1681
|
+
# <tt>persisted?</tt> is used when calculating the URL for an object.
|
1682
|
+
# If the object is not persisted, a form for that object, for instance,
|
1683
|
+
# will route to the create action. If it is persisted, a form for the
|
1684
|
+
# object will route to the update action.
|
1685
|
+
def test_persisted?: () -> untyped
|
1686
|
+
|
1687
|
+
# Passes if the object's model responds to <tt>model_name</tt> both as
|
1688
|
+
# an instance method and as a class method, and if calling this method
|
1689
|
+
# returns a string with some convenience methods: <tt>:human</tt>,
|
1690
|
+
# <tt>:singular</tt> and <tt>:plural</tt>.
|
1691
|
+
#
|
1692
|
+
# Check ActiveModel::Naming for more information.
|
1693
|
+
def test_model_naming: () -> untyped
|
1694
|
+
|
1695
|
+
# Passes if the object's model responds to <tt>errors</tt> and if calling
|
1696
|
+
# <tt>[](attribute)</tt> on the result of this method returns an array.
|
1697
|
+
# Fails otherwise.
|
1698
|
+
#
|
1699
|
+
# <tt>errors[attribute]</tt> is used to retrieve the errors of a model
|
1700
|
+
# for a given attribute. If errors are present, the method should return
|
1701
|
+
# an array of strings that are the errors for the attribute in question.
|
1702
|
+
# If localization is used, the strings should be localized for the current
|
1703
|
+
# locale. If no error is present, the method should return an empty array.
|
1704
|
+
def test_errors_aref: () -> untyped
|
1705
|
+
|
1706
|
+
def model: () -> untyped
|
1707
|
+
|
1708
|
+
def assert_boolean: (untyped result, untyped name) -> untyped
|
1709
|
+
end
|
1710
|
+
|
1711
|
+
# == Active \Model \Basic \Model
|
1712
|
+
#
|
1713
|
+
# Includes the required interface for an object to interact with
|
1714
|
+
# Action Pack and Action View, using different Active Model modules.
|
1715
|
+
# It includes model name introspections, conversions, translations and
|
1716
|
+
# validations. Besides that, it allows you to initialize the object with a
|
1717
|
+
# hash of attributes, pretty much like Active Record does.
|
1718
|
+
#
|
1719
|
+
# A minimal implementation could be:
|
1720
|
+
#
|
1721
|
+
# class Person
|
1722
|
+
# include ActiveModel::Model
|
1723
|
+
# attr_accessor :name, :age
|
1724
|
+
# end
|
1725
|
+
#
|
1726
|
+
# person = Person.new(name: 'bob', age: '18')
|
1727
|
+
# person.name # => "bob"
|
1728
|
+
# person.age # => "18"
|
1729
|
+
#
|
1730
|
+
# Note that, by default, <tt>ActiveModel::Model</tt> implements <tt>persisted?</tt>
|
1731
|
+
# to return +false+, which is the most common case. You may want to override
|
1732
|
+
# it in your class to simulate a different scenario:
|
1733
|
+
#
|
1734
|
+
# class Person
|
1735
|
+
# include ActiveModel::Model
|
1736
|
+
# attr_accessor :id, :name
|
1737
|
+
#
|
1738
|
+
# def persisted?
|
1739
|
+
# self.id == 1
|
1740
|
+
# end
|
1741
|
+
# end
|
1742
|
+
#
|
1743
|
+
# person = Person.new(id: 1, name: 'bob')
|
1744
|
+
# person.persisted? # => true
|
1745
|
+
#
|
1746
|
+
# Also, if for some reason you need to run code on <tt>initialize</tt>, make
|
1747
|
+
# sure you call +super+ if you want the attributes hash initialization to
|
1748
|
+
# happen.
|
1749
|
+
#
|
1750
|
+
# class Person
|
1751
|
+
# include ActiveModel::Model
|
1752
|
+
# attr_accessor :id, :name, :omg
|
1753
|
+
#
|
1754
|
+
# def initialize(attributes={})
|
1755
|
+
# super
|
1756
|
+
# @omg ||= true
|
1757
|
+
# end
|
1758
|
+
# end
|
1759
|
+
#
|
1760
|
+
# person = Person.new(id: 1, name: 'bob')
|
1761
|
+
# person.omg # => true
|
1762
|
+
#
|
1763
|
+
# For more detailed information on other functionalities available, please
|
1764
|
+
# refer to the specific modules included in <tt>ActiveModel::Model</tt>
|
1765
|
+
# (see below).
|
1766
|
+
module ActiveModel::Model
|
1767
|
+
extend ActiveSupport::Concern
|
1768
|
+
|
1769
|
+
include ActiveModel::AttributeAssignment
|
1770
|
+
|
1771
|
+
include ActiveModel::Validations
|
1772
|
+
|
1773
|
+
include ActiveModel::Conversion
|
1774
|
+
|
1775
|
+
extend ActiveModel::Naming
|
1776
|
+
|
1777
|
+
extend ActiveModel::Translation
|
1778
|
+
|
1779
|
+
# Initializes a new model with the given +params+.
|
1780
|
+
#
|
1781
|
+
# class Person
|
1782
|
+
# include ActiveModel::Model
|
1783
|
+
# attr_accessor :name, :age
|
1784
|
+
# end
|
1785
|
+
#
|
1786
|
+
# person = Person.new(name: 'bob', age: '18')
|
1787
|
+
# person.name # => "bob"
|
1788
|
+
# person.age # => "18"
|
1789
|
+
def initialize: (?::Hash[untyped, untyped] attributes) -> untyped
|
1790
|
+
|
1791
|
+
# Indicates if the model is persisted. Default is +false+.
|
1792
|
+
#
|
1793
|
+
# class Person
|
1794
|
+
# include ActiveModel::Model
|
1795
|
+
# attr_accessor :id, :name
|
1796
|
+
# end
|
1797
|
+
#
|
1798
|
+
# person = Person.new(id: 1, name: 'bob')
|
1799
|
+
# person.persisted? # => false
|
1800
|
+
def persisted?: () -> ::FalseClass
|
1801
|
+
end
|
1802
|
+
|
1803
|
+
class ActiveModel::Name
|
1804
|
+
include Comparable
|
1805
|
+
|
1806
|
+
attr_reader singular: untyped
|
1807
|
+
|
1808
|
+
attr_reader plural: untyped
|
1809
|
+
|
1810
|
+
attr_reader element: untyped
|
1811
|
+
|
1812
|
+
attr_reader collection: untyped
|
1813
|
+
|
1814
|
+
attr_reader singular_route_key: untyped
|
1815
|
+
|
1816
|
+
attr_reader route_key: untyped
|
1817
|
+
|
1818
|
+
attr_reader param_key: untyped
|
1819
|
+
|
1820
|
+
attr_reader i18n_key: untyped
|
1821
|
+
|
1822
|
+
attr_reader name: untyped
|
1823
|
+
|
1824
|
+
# Returns a new ActiveModel::Name instance. By default, the +namespace+
|
1825
|
+
# and +name+ option will take the namespace and name of the given class
|
1826
|
+
# respectively.
|
1827
|
+
#
|
1828
|
+
# module Foo
|
1829
|
+
# class Bar
|
1830
|
+
# end
|
1831
|
+
# end
|
1832
|
+
#
|
1833
|
+
# ActiveModel::Name.new(Foo::Bar).to_s
|
1834
|
+
# # => "Foo::Bar"
|
1835
|
+
def initialize: (untyped klass, ?untyped? namespace, ?untyped? name) -> untyped
|
1836
|
+
|
1837
|
+
# Transform the model name into a more human format, using I18n. By default,
|
1838
|
+
# it will underscore then humanize the class name.
|
1839
|
+
#
|
1840
|
+
# class BlogPost
|
1841
|
+
# extend ActiveModel::Naming
|
1842
|
+
# end
|
1843
|
+
#
|
1844
|
+
# BlogPost.model_name.human # => "Blog post"
|
1845
|
+
#
|
1846
|
+
# Specify +options+ with additional translating options.
|
1847
|
+
def human: (?::Hash[untyped, untyped] options) -> untyped
|
1848
|
+
|
1849
|
+
def _singularize: (untyped string) -> untyped
|
1850
|
+
end
|
1851
|
+
|
1852
|
+
# == Active \Model \Naming
|
1853
|
+
#
|
1854
|
+
# Creates a +model_name+ method on your object.
|
1855
|
+
#
|
1856
|
+
# To implement, just extend ActiveModel::Naming in your object:
|
1857
|
+
#
|
1858
|
+
# class BookCover
|
1859
|
+
# extend ActiveModel::Naming
|
1860
|
+
# end
|
1861
|
+
#
|
1862
|
+
# BookCover.model_name.name # => "BookCover"
|
1863
|
+
# BookCover.model_name.human # => "Book cover"
|
1864
|
+
#
|
1865
|
+
# BookCover.model_name.i18n_key # => :book_cover
|
1866
|
+
# BookModule::BookCover.model_name.i18n_key # => :"book_module/book_cover"
|
1867
|
+
#
|
1868
|
+
# Providing the functionality that ActiveModel::Naming provides in your object
|
1869
|
+
# is required to pass the \Active \Model Lint test. So either extending the
|
1870
|
+
# provided method below, or rolling your own is required.
|
1871
|
+
module ActiveModel::Naming
|
1872
|
+
def self.extended: (untyped base) -> untyped
|
1873
|
+
|
1874
|
+
# Returns an ActiveModel::Name object for module. It can be
|
1875
|
+
# used to retrieve all kinds of naming-related information
|
1876
|
+
# (See ActiveModel::Name for more information).
|
1877
|
+
#
|
1878
|
+
# class Person
|
1879
|
+
# extend ActiveModel::Naming
|
1880
|
+
# end
|
1881
|
+
#
|
1882
|
+
# Person.model_name.name # => "Person"
|
1883
|
+
# Person.model_name.class # => ActiveModel::Name
|
1884
|
+
# Person.model_name.singular # => "person"
|
1885
|
+
# Person.model_name.plural # => "people"
|
1886
|
+
def model_name: () -> untyped
|
1887
|
+
|
1888
|
+
# Returns the plural class name of a record or class.
|
1889
|
+
#
|
1890
|
+
# ActiveModel::Naming.plural(post) # => "posts"
|
1891
|
+
# ActiveModel::Naming.plural(Highrise::Person) # => "highrise_people"
|
1892
|
+
def self.plural: (untyped record_or_class) -> untyped
|
1893
|
+
|
1894
|
+
# Returns the singular class name of a record or class.
|
1895
|
+
#
|
1896
|
+
# ActiveModel::Naming.singular(post) # => "post"
|
1897
|
+
# ActiveModel::Naming.singular(Highrise::Person) # => "highrise_person"
|
1898
|
+
def self.singular: (untyped record_or_class) -> untyped
|
1899
|
+
|
1900
|
+
# Identifies whether the class name of a record or class is uncountable.
|
1901
|
+
#
|
1902
|
+
# ActiveModel::Naming.uncountable?(Sheep) # => true
|
1903
|
+
# ActiveModel::Naming.uncountable?(Post) # => false
|
1904
|
+
def self.uncountable?: (untyped record_or_class) -> untyped
|
1905
|
+
|
1906
|
+
# Returns string to use while generating route names. It differs for
|
1907
|
+
# namespaced models regarding whether it's inside isolated engine.
|
1908
|
+
#
|
1909
|
+
# # For isolated engine:
|
1910
|
+
# ActiveModel::Naming.singular_route_key(Blog::Post) # => "post"
|
1911
|
+
#
|
1912
|
+
# # For shared engine:
|
1913
|
+
# ActiveModel::Naming.singular_route_key(Blog::Post) # => "blog_post"
|
1914
|
+
def self.singular_route_key: (untyped record_or_class) -> untyped
|
1915
|
+
|
1916
|
+
# Returns string to use while generating route names. It differs for
|
1917
|
+
# namespaced models regarding whether it's inside isolated engine.
|
1918
|
+
#
|
1919
|
+
# # For isolated engine:
|
1920
|
+
# ActiveModel::Naming.route_key(Blog::Post) # => "posts"
|
1921
|
+
#
|
1922
|
+
# # For shared engine:
|
1923
|
+
# ActiveModel::Naming.route_key(Blog::Post) # => "blog_posts"
|
1924
|
+
#
|
1925
|
+
# The route key also considers if the noun is uncountable and, in
|
1926
|
+
# such cases, automatically appends _index.
|
1927
|
+
def self.route_key: (untyped record_or_class) -> untyped
|
1928
|
+
|
1929
|
+
# Returns string to use for params names. It differs for
|
1930
|
+
# namespaced models regarding whether it's inside isolated engine.
|
1931
|
+
#
|
1932
|
+
# # For isolated engine:
|
1933
|
+
# ActiveModel::Naming.param_key(Blog::Post) # => "post"
|
1934
|
+
#
|
1935
|
+
# # For shared engine:
|
1936
|
+
# ActiveModel::Naming.param_key(Blog::Post) # => "blog_post"
|
1937
|
+
def self.param_key: (untyped record_or_class) -> untyped
|
1938
|
+
|
1939
|
+
def self.model_name_from_record_or_class: (untyped record_or_class) -> untyped
|
1940
|
+
end
|
1941
|
+
|
1942
|
+
class ActiveModel::Railtie < Rails::Railtie
|
1943
|
+
end
|
1944
|
+
|
1945
|
+
module ActiveModel::Serializers
|
1946
|
+
extend ActiveSupport::Autoload
|
1947
|
+
end
|
1948
|
+
|
1949
|
+
module ActiveModel::SecurePassword
|
1950
|
+
extend ActiveSupport::Concern
|
1951
|
+
|
1952
|
+
attr_accessor min_cost: untyped
|
1953
|
+
end
|
1954
|
+
|
1955
|
+
# BCrypt hash function can handle maximum 72 bytes, and if we pass
|
1956
|
+
# password of length more than 72 bytes it ignores extra characters.
|
1957
|
+
# Hence need to put a restriction on password length.
|
1958
|
+
ActiveModel::SecurePassword::MAX_PASSWORD_LENGTH_ALLOWED: ::Integer
|
1959
|
+
|
1960
|
+
module ActiveModel::SecurePassword::ClassMethods
|
1961
|
+
# Adds methods to set and authenticate against a BCrypt password.
|
1962
|
+
# This mechanism requires you to have a +XXX_digest+ attribute.
|
1963
|
+
# Where +XXX+ is the attribute name of your desired password.
|
1964
|
+
#
|
1965
|
+
# The following validations are added automatically:
|
1966
|
+
# * Password must be present on creation
|
1967
|
+
# * Password length should be less than or equal to 72 bytes
|
1968
|
+
# * Confirmation of password (using a +XXX_confirmation+ attribute)
|
1969
|
+
#
|
1970
|
+
# If confirmation validation is not needed, simply leave out the
|
1971
|
+
# value for +XXX_confirmation+ (i.e. don't provide a form field for
|
1972
|
+
# it). When this attribute has a +nil+ value, the validation will not be
|
1973
|
+
# triggered.
|
1974
|
+
#
|
1975
|
+
# For further customizability, it is possible to suppress the default
|
1976
|
+
# validations by passing <tt>validations: false</tt> as an argument.
|
1977
|
+
#
|
1978
|
+
# Add bcrypt (~> 3.1.7) to Gemfile to use #has_secure_password:
|
1979
|
+
#
|
1980
|
+
# gem 'bcrypt', '~> 3.1.7'
|
1981
|
+
#
|
1982
|
+
# Example using Active Record (which automatically includes ActiveModel::SecurePassword):
|
1983
|
+
#
|
1984
|
+
# # Schema: User(name:string, password_digest:string, recovery_password_digest:string)
|
1985
|
+
# class User < ActiveRecord::Base
|
1986
|
+
# has_secure_password
|
1987
|
+
# has_secure_password :recovery_password, validations: false
|
1988
|
+
# end
|
1989
|
+
#
|
1990
|
+
# user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
|
1991
|
+
# user.save # => false, password required
|
1992
|
+
# user.password = 'mUc3m00RsqyRe'
|
1993
|
+
# user.save # => false, confirmation doesn't match
|
1994
|
+
# user.password_confirmation = 'mUc3m00RsqyRe'
|
1995
|
+
# user.save # => true
|
1996
|
+
# user.recovery_password = "42password"
|
1997
|
+
# user.recovery_password_digest # => "$2a$04$iOfhwahFymCs5weB3BNH/uXkTG65HR.qpW.bNhEjFP3ftli3o5DQC"
|
1998
|
+
# user.save # => true
|
1999
|
+
# user.authenticate('notright') # => false
|
2000
|
+
# user.authenticate('mUc3m00RsqyRe') # => user
|
2001
|
+
# user.authenticate_recovery_password('42password') # => user
|
2002
|
+
# User.find_by(name: 'david').try(:authenticate, 'notright') # => false
|
2003
|
+
# User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user
|
2004
|
+
def has_secure_password: (?::Symbol attribute, ?validations: bool validations) -> untyped
|
2005
|
+
end
|
2006
|
+
|
2007
|
+
class ActiveModel::SecurePassword::InstanceMethodsOnActivation < Module
|
2008
|
+
def initialize: (untyped attribute) -> untyped
|
2009
|
+
end
|
2010
|
+
|
2011
|
+
# == Active \Model \Serialization
|
2012
|
+
#
|
2013
|
+
# Provides a basic serialization to a serializable_hash for your objects.
|
2014
|
+
#
|
2015
|
+
# A minimal implementation could be:
|
2016
|
+
#
|
2017
|
+
# class Person
|
2018
|
+
# include ActiveModel::Serialization
|
2019
|
+
#
|
2020
|
+
# attr_accessor :name
|
2021
|
+
#
|
2022
|
+
# def attributes
|
2023
|
+
# {'name' => nil}
|
2024
|
+
# end
|
2025
|
+
# end
|
2026
|
+
#
|
2027
|
+
# Which would provide you with:
|
2028
|
+
#
|
2029
|
+
# person = Person.new
|
2030
|
+
# person.serializable_hash # => {"name"=>nil}
|
2031
|
+
# person.name = "Bob"
|
2032
|
+
# person.serializable_hash # => {"name"=>"Bob"}
|
2033
|
+
#
|
2034
|
+
# An +attributes+ hash must be defined and should contain any attributes you
|
2035
|
+
# need to be serialized. Attributes must be strings, not symbols.
|
2036
|
+
# When called, serializable hash will use instance methods that match the name
|
2037
|
+
# of the attributes hash's keys. In order to override this behavior, take a look
|
2038
|
+
# at the private method +read_attribute_for_serialization+.
|
2039
|
+
#
|
2040
|
+
# ActiveModel::Serializers::JSON module automatically includes
|
2041
|
+
# the <tt>ActiveModel::Serialization</tt> module, so there is no need to
|
2042
|
+
# explicitly include <tt>ActiveModel::Serialization</tt>.
|
2043
|
+
#
|
2044
|
+
# A minimal implementation including JSON would be:
|
2045
|
+
#
|
2046
|
+
# class Person
|
2047
|
+
# include ActiveModel::Serializers::JSON
|
2048
|
+
#
|
2049
|
+
# attr_accessor :name
|
2050
|
+
#
|
2051
|
+
# def attributes
|
2052
|
+
# {'name' => nil}
|
2053
|
+
# end
|
2054
|
+
# end
|
2055
|
+
#
|
2056
|
+
# Which would provide you with:
|
2057
|
+
#
|
2058
|
+
# person = Person.new
|
2059
|
+
# person.serializable_hash # => {"name"=>nil}
|
2060
|
+
# person.as_json # => {"name"=>nil}
|
2061
|
+
# person.to_json # => "{\"name\":null}"
|
2062
|
+
#
|
2063
|
+
# person.name = "Bob"
|
2064
|
+
# person.serializable_hash # => {"name"=>"Bob"}
|
2065
|
+
# person.as_json # => {"name"=>"Bob"}
|
2066
|
+
# person.to_json # => "{\"name\":\"Bob\"}"
|
2067
|
+
#
|
2068
|
+
# Valid options are <tt>:only</tt>, <tt>:except</tt>, <tt>:methods</tt> and
|
2069
|
+
# <tt>:include</tt>. The following are all valid examples:
|
2070
|
+
#
|
2071
|
+
# person.serializable_hash(only: 'name')
|
2072
|
+
# person.serializable_hash(include: :address)
|
2073
|
+
# person.serializable_hash(include: { address: { only: 'city' }})
|
2074
|
+
module ActiveModel::Serialization
|
2075
|
+
# Returns a serialized hash of your object.
|
2076
|
+
#
|
2077
|
+
# class Person
|
2078
|
+
# include ActiveModel::Serialization
|
2079
|
+
#
|
2080
|
+
# attr_accessor :name, :age
|
2081
|
+
#
|
2082
|
+
# def attributes
|
2083
|
+
# {'name' => nil, 'age' => nil}
|
2084
|
+
# end
|
2085
|
+
#
|
2086
|
+
# def capitalized_name
|
2087
|
+
# name.capitalize
|
2088
|
+
# end
|
2089
|
+
# end
|
2090
|
+
#
|
2091
|
+
# person = Person.new
|
2092
|
+
# person.name = 'bob'
|
2093
|
+
# person.age = 22
|
2094
|
+
# person.serializable_hash # => {"name"=>"bob", "age"=>22}
|
2095
|
+
# person.serializable_hash(only: :name) # => {"name"=>"bob"}
|
2096
|
+
# person.serializable_hash(except: :name) # => {"age"=>22}
|
2097
|
+
# person.serializable_hash(methods: :capitalized_name)
|
2098
|
+
# # => {"name"=>"bob", "age"=>22, "capitalized_name"=>"Bob"}
|
2099
|
+
#
|
2100
|
+
# Example with <tt>:include</tt> option
|
2101
|
+
#
|
2102
|
+
# class User
|
2103
|
+
# include ActiveModel::Serializers::JSON
|
2104
|
+
# attr_accessor :name, :notes # Emulate has_many :notes
|
2105
|
+
# def attributes
|
2106
|
+
# {'name' => nil}
|
2107
|
+
# end
|
2108
|
+
# end
|
2109
|
+
#
|
2110
|
+
# class Note
|
2111
|
+
# include ActiveModel::Serializers::JSON
|
2112
|
+
# attr_accessor :title, :text
|
2113
|
+
# def attributes
|
2114
|
+
# {'title' => nil, 'text' => nil}
|
2115
|
+
# end
|
2116
|
+
# end
|
2117
|
+
#
|
2118
|
+
# note = Note.new
|
2119
|
+
# note.title = 'Battle of Austerlitz'
|
2120
|
+
# note.text = 'Some text here'
|
2121
|
+
#
|
2122
|
+
# user = User.new
|
2123
|
+
# user.name = 'Napoleon'
|
2124
|
+
# user.notes = [note]
|
2125
|
+
#
|
2126
|
+
# user.serializable_hash
|
2127
|
+
# # => {"name" => "Napoleon"}
|
2128
|
+
# user.serializable_hash(include: { notes: { only: 'title' }})
|
2129
|
+
# # => {"name" => "Napoleon", "notes" => [{"title"=>"Battle of Austerlitz"}]}
|
2130
|
+
def serializable_hash: (?untyped? options) -> untyped
|
2131
|
+
|
2132
|
+
def serializable_add_includes: (?::Hash[untyped, untyped] options) { (untyped, untyped, untyped) -> untyped } -> (nil | untyped)
|
2133
|
+
end
|
2134
|
+
|
2135
|
+
# == Active \Model \JSON \Serializer
|
2136
|
+
module ActiveModel::Serializers::JSON
|
2137
|
+
extend ActiveSupport::Concern
|
2138
|
+
|
2139
|
+
include ActiveModel::Serialization
|
2140
|
+
|
2141
|
+
extend ActiveModel::Naming
|
2142
|
+
|
2143
|
+
# Returns a hash representing the model. Some configuration can be
|
2144
|
+
# passed through +options+.
|
2145
|
+
#
|
2146
|
+
# The option <tt>include_root_in_json</tt> controls the top-level behavior
|
2147
|
+
# of +as_json+. If +true+, +as_json+ will emit a single root node named
|
2148
|
+
# after the object's type. The default value for <tt>include_root_in_json</tt>
|
2149
|
+
# option is +false+.
|
2150
|
+
#
|
2151
|
+
# user = User.find(1)
|
2152
|
+
# user.as_json
|
2153
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
2154
|
+
# # "created_at" => "2006-08-01T17:27:133.000Z", "awesome" => true}
|
2155
|
+
#
|
2156
|
+
# ActiveRecord::Base.include_root_in_json = true
|
2157
|
+
#
|
2158
|
+
# user.as_json
|
2159
|
+
# # => { "user" => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
2160
|
+
# # "created_at" => "2006-08-01T17:27:13.000Z", "awesome" => true } }
|
2161
|
+
#
|
2162
|
+
# This behavior can also be achieved by setting the <tt>:root</tt> option
|
2163
|
+
# to +true+ as in:
|
2164
|
+
#
|
2165
|
+
# user = User.find(1)
|
2166
|
+
# user.as_json(root: true)
|
2167
|
+
# # => { "user" => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
2168
|
+
# # "created_at" => "2006-08-01T17:27:13.000Z", "awesome" => true } }
|
2169
|
+
#
|
2170
|
+
# Without any +options+, the returned Hash will include all the model's
|
2171
|
+
# attributes.
|
2172
|
+
#
|
2173
|
+
# user = User.find(1)
|
2174
|
+
# user.as_json
|
2175
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
2176
|
+
# # "created_at" => "2006-08-01T17:27:13.000Z", "awesome" => true}
|
2177
|
+
#
|
2178
|
+
# The <tt>:only</tt> and <tt>:except</tt> options can be used to limit
|
2179
|
+
# the attributes included, and work similar to the +attributes+ method.
|
2180
|
+
#
|
2181
|
+
# user.as_json(only: [:id, :name])
|
2182
|
+
# # => { "id" => 1, "name" => "Konata Izumi" }
|
2183
|
+
#
|
2184
|
+
# user.as_json(except: [:id, :created_at, :age])
|
2185
|
+
# # => { "name" => "Konata Izumi", "awesome" => true }
|
2186
|
+
#
|
2187
|
+
# To include the result of some method calls on the model use <tt>:methods</tt>:
|
2188
|
+
#
|
2189
|
+
# user.as_json(methods: :permalink)
|
2190
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
2191
|
+
# # "created_at" => "2006-08-01T17:27:13.000Z", "awesome" => true,
|
2192
|
+
# # "permalink" => "1-konata-izumi" }
|
2193
|
+
#
|
2194
|
+
# To include associations use <tt>:include</tt>:
|
2195
|
+
#
|
2196
|
+
# user.as_json(include: :posts)
|
2197
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
2198
|
+
# # "created_at" => "2006-08-01T17:27:13.000Z", "awesome" => true,
|
2199
|
+
# # "posts" => [ { "id" => 1, "author_id" => 1, "title" => "Welcome to the weblog" },
|
2200
|
+
# # { "id" => 2, "author_id" => 1, "title" => "So I was thinking" } ] }
|
2201
|
+
#
|
2202
|
+
# Second level and higher order associations work as well:
|
2203
|
+
#
|
2204
|
+
# user.as_json(include: { posts: {
|
2205
|
+
# include: { comments: {
|
2206
|
+
# only: :body } },
|
2207
|
+
# only: :title } })
|
2208
|
+
# # => { "id" => 1, "name" => "Konata Izumi", "age" => 16,
|
2209
|
+
# # "created_at" => "2006-08-01T17:27:13.000Z", "awesome" => true,
|
2210
|
+
# # "posts" => [ { "comments" => [ { "body" => "1st post!" }, { "body" => "Second!" } ],
|
2211
|
+
# # "title" => "Welcome to the weblog" },
|
2212
|
+
# # { "comments" => [ { "body" => "Don't think too hard" } ],
|
2213
|
+
# # "title" => "So I was thinking" } ] }
|
2214
|
+
def as_json: (?untyped? options) -> untyped
|
2215
|
+
|
2216
|
+
# Sets the model +attributes+ from a JSON string. Returns +self+.
|
2217
|
+
#
|
2218
|
+
# class Person
|
2219
|
+
# include ActiveModel::Serializers::JSON
|
2220
|
+
#
|
2221
|
+
# attr_accessor :name, :age, :awesome
|
2222
|
+
#
|
2223
|
+
# def attributes=(hash)
|
2224
|
+
# hash.each do |key, value|
|
2225
|
+
# send("#{key}=", value)
|
2226
|
+
# end
|
2227
|
+
# end
|
2228
|
+
#
|
2229
|
+
# def attributes
|
2230
|
+
# instance_values
|
2231
|
+
# end
|
2232
|
+
# end
|
2233
|
+
#
|
2234
|
+
# json = { name: 'bob', age: 22, awesome:true }.to_json
|
2235
|
+
# person = Person.new
|
2236
|
+
# person.from_json(json) # => #<Person:0x007fec5e7a0088 @age=22, @awesome=true, @name="bob">
|
2237
|
+
# person.name # => "bob"
|
2238
|
+
# person.age # => 22
|
2239
|
+
# person.awesome # => true
|
2240
|
+
#
|
2241
|
+
# The default value for +include_root+ is +false+. You can change it to
|
2242
|
+
# +true+ if the given JSON string includes a single root node.
|
2243
|
+
#
|
2244
|
+
# json = { person: { name: 'bob', age: 22, awesome:true } }.to_json
|
2245
|
+
# person = Person.new
|
2246
|
+
# person.from_json(json, true) # => #<Person:0x007fec5e7a0088 @age=22, @awesome=true, @name="bob">
|
2247
|
+
# person.name # => "bob"
|
2248
|
+
# person.age # => 22
|
2249
|
+
# person.awesome # => true
|
2250
|
+
def from_json: (untyped json, ?untyped include_root) -> untyped
|
2251
|
+
end
|
2252
|
+
|
2253
|
+
# == Active \Model \Translation
|
2254
|
+
#
|
2255
|
+
# Provides integration between your object and the Rails internationalization
|
2256
|
+
# (i18n) framework.
|
2257
|
+
#
|
2258
|
+
# A minimal implementation could be:
|
2259
|
+
#
|
2260
|
+
# class TranslatedPerson
|
2261
|
+
# extend ActiveModel::Translation
|
2262
|
+
# end
|
2263
|
+
#
|
2264
|
+
# TranslatedPerson.human_attribute_name('my_attribute')
|
2265
|
+
# # => "My attribute"
|
2266
|
+
#
|
2267
|
+
# This also provides the required class methods for hooking into the
|
2268
|
+
# Rails internationalization API, including being able to define a
|
2269
|
+
# class based +i18n_scope+ and +lookup_ancestors+ to find translations in
|
2270
|
+
# parent classes.
|
2271
|
+
module ActiveModel::Translation
|
2272
|
+
include ActiveModel::Naming
|
2273
|
+
|
2274
|
+
# Returns the +i18n_scope+ for the class. Overwrite if you want custom lookup.
|
2275
|
+
def i18n_scope: () -> :activemodel
|
2276
|
+
|
2277
|
+
# When localizing a string, it goes through the lookup returned by this
|
2278
|
+
# method, which is used in ActiveModel::Name#human,
|
2279
|
+
# ActiveModel::Errors#full_messages and
|
2280
|
+
# ActiveModel::Translation#human_attribute_name.
|
2281
|
+
def lookup_ancestors: () -> untyped
|
2282
|
+
|
2283
|
+
# Transforms attribute names into a more human format, such as "First name"
|
2284
|
+
# instead of "first_name".
|
2285
|
+
#
|
2286
|
+
# Person.human_attribute_name("first_name") # => "First name"
|
2287
|
+
#
|
2288
|
+
# Specify +options+ with additional translating options.
|
2289
|
+
def human_attribute_name: (untyped attribute, ?::Hash[untyped, untyped] options) -> untyped
|
2290
|
+
end
|
2291
|
+
|
2292
|
+
module ActiveModel::Type
|
2293
|
+
attr_accessor registry: untyped
|
2294
|
+
|
2295
|
+
# Add a new type to the registry, allowing it to be gotten through ActiveModel::Type#lookup
|
2296
|
+
def self.register: (untyped type_name, ?untyped? klass, **untyped options) { () -> untyped } -> untyped
|
2297
|
+
|
2298
|
+
def self.lookup: (*untyped args, **untyped kwargs) -> untyped
|
2299
|
+
|
2300
|
+
def self.default_value: () -> untyped
|
2301
|
+
end
|
2302
|
+
|
2303
|
+
class ActiveModel::Type::BigInteger < Integer
|
2304
|
+
def max_value: () -> untyped
|
2305
|
+
end
|
2306
|
+
|
2307
|
+
class ActiveModel::Type::Binary < Value
|
2308
|
+
# :nodoc:
|
2309
|
+
def `type`: () -> :binary
|
2310
|
+
|
2311
|
+
def binary?: () -> ::TrueClass
|
2312
|
+
|
2313
|
+
def cast: (untyped value) -> untyped
|
2314
|
+
|
2315
|
+
def serialize: (untyped value) -> (nil | untyped)
|
2316
|
+
|
2317
|
+
def changed_in_place?: (untyped raw_old_value, untyped value) -> untyped
|
2318
|
+
end
|
2319
|
+
|
2320
|
+
class ActiveModel::Type::Binary::Data
|
2321
|
+
# :nodoc:
|
2322
|
+
def initialize: (untyped value) -> untyped
|
2323
|
+
|
2324
|
+
def to_s: () -> untyped
|
2325
|
+
|
2326
|
+
def hex: () -> untyped
|
2327
|
+
|
2328
|
+
def ==: (untyped other) -> untyped
|
2329
|
+
end
|
2330
|
+
|
2331
|
+
# == Active \Model \Type \Boolean
|
2332
|
+
#
|
2333
|
+
# A class that behaves like a boolean type, including rules for coercion of user input.
|
2334
|
+
#
|
2335
|
+
# === Coercion
|
2336
|
+
# Values set from user input will first be coerced into the appropriate ruby type.
|
2337
|
+
# Coercion behavior is roughly mapped to Ruby's boolean semantics.
|
2338
|
+
#
|
2339
|
+
# - "false", "f" , "0", +0+ or any other value in +FALSE_VALUES+ will be coerced to +false+
|
2340
|
+
# - Empty strings are coerced to +nil+
|
2341
|
+
# - All other values will be coerced to +true+
|
2342
|
+
class ActiveModel::Type::Boolean < Value
|
2343
|
+
def `type`: () -> :boolean
|
2344
|
+
|
2345
|
+
def serialize: (untyped value) -> untyped
|
2346
|
+
|
2347
|
+
def cast_value: (untyped value) -> untyped
|
2348
|
+
end
|
2349
|
+
|
2350
|
+
ActiveModel::Type::Boolean::FALSE_VALUES: untyped
|
2351
|
+
|
2352
|
+
class ActiveModel::Type::Date < Value
|
2353
|
+
# :nodoc:
|
2354
|
+
include Helpers::Timezone
|
2355
|
+
|
2356
|
+
def `type`: () -> :date
|
2357
|
+
|
2358
|
+
def type_cast_for_schema: (untyped value) -> untyped
|
2359
|
+
|
2360
|
+
def cast_value: (untyped value) -> untyped
|
2361
|
+
|
2362
|
+
def fast_string_to_date: (untyped string) -> untyped
|
2363
|
+
|
2364
|
+
def fallback_string_to_date: (untyped string) -> untyped
|
2365
|
+
|
2366
|
+
def new_date: (untyped year, untyped mon, untyped mday) -> untyped
|
2367
|
+
|
2368
|
+
def value_from_multiparameter_assignment: () -> untyped
|
2369
|
+
end
|
2370
|
+
|
2371
|
+
ActiveModel::Type::Date::ISO_DATE: untyped
|
2372
|
+
|
2373
|
+
class ActiveModel::Type::DateTime < Value
|
2374
|
+
# :nodoc:
|
2375
|
+
include Helpers::Timezone
|
2376
|
+
|
2377
|
+
include Helpers::TimeValue
|
2378
|
+
|
2379
|
+
def `type`: () -> :datetime
|
2380
|
+
|
2381
|
+
def cast_value: (untyped value) -> (untyped | nil)
|
2382
|
+
|
2383
|
+
# '0.123456' -> 123456
|
2384
|
+
# '1.123456' -> 123456
|
2385
|
+
def microseconds: (untyped time) -> untyped
|
2386
|
+
|
2387
|
+
def fallback_string_to_time: (untyped string) -> untyped
|
2388
|
+
|
2389
|
+
def value_from_multiparameter_assignment: (untyped values_hash) -> untyped
|
2390
|
+
end
|
2391
|
+
|
2392
|
+
class ActiveModel::Type::Decimal < Value
|
2393
|
+
# :nodoc:
|
2394
|
+
include Helpers::Numeric
|
2395
|
+
|
2396
|
+
def `type`: () -> :decimal
|
2397
|
+
|
2398
|
+
def type_cast_for_schema: (untyped value) -> untyped
|
2399
|
+
|
2400
|
+
def cast_value: (untyped value) -> untyped
|
2401
|
+
|
2402
|
+
def convert_float_to_big_decimal: (untyped value) -> untyped
|
2403
|
+
|
2404
|
+
def float_precision: () -> untyped
|
2405
|
+
|
2406
|
+
def apply_scale: (untyped value) -> untyped
|
2407
|
+
end
|
2408
|
+
|
2409
|
+
ActiveModel::Type::Decimal::BIGDECIMAL_PRECISION: ::Integer
|
2410
|
+
|
2411
|
+
class ActiveModel::Type::Float < Value
|
2412
|
+
# :nodoc:
|
2413
|
+
include Helpers::Numeric
|
2414
|
+
|
2415
|
+
def `type`: () -> :float
|
2416
|
+
|
2417
|
+
def type_cast_for_schema: (untyped value) -> ("::Float::NAN" | untyped)
|
2418
|
+
|
2419
|
+
def cast_value: (untyped value) -> untyped
|
2420
|
+
end
|
2421
|
+
|
2422
|
+
module ActiveModel::Type::Helpers
|
2423
|
+
end
|
2424
|
+
|
2425
|
+
# :nodoc: all
|
2426
|
+
class ActiveModel::Type::Helpers::AcceptsMultiparameterTime < Module
|
2427
|
+
def initialize: (?defaults: ::Hash[untyped, untyped] defaults) -> (nil | untyped)
|
2428
|
+
end
|
2429
|
+
|
2430
|
+
# :nodoc: all
|
2431
|
+
module ActiveModel::Type::Helpers::Mutable
|
2432
|
+
def cast: (untyped value) -> untyped
|
2433
|
+
|
2434
|
+
# +raw_old_value+ will be the `_before_type_cast` version of the
|
2435
|
+
# value (likely a string). +new_value+ will be the current, type
|
2436
|
+
# cast value.
|
2437
|
+
def changed_in_place?: (untyped raw_old_value, untyped new_value) -> untyped
|
2438
|
+
end
|
2439
|
+
|
2440
|
+
# :nodoc: all
|
2441
|
+
module ActiveModel::Type::Helpers::Numeric
|
2442
|
+
def serialize: (untyped value) -> untyped
|
2443
|
+
|
2444
|
+
def cast: (untyped value) -> untyped
|
2445
|
+
|
2446
|
+
def changed?: (untyped old_value, untyped _new_value, untyped new_value_before_type_cast) -> untyped
|
2447
|
+
|
2448
|
+
def number_to_non_number?: (untyped old_value, untyped new_value_before_type_cast) -> untyped
|
2449
|
+
|
2450
|
+
def non_numeric_string?: (untyped value) -> untyped
|
2451
|
+
end
|
2452
|
+
|
2453
|
+
ActiveModel::Type::Helpers::Numeric::NUMERIC_REGEX: untyped
|
2454
|
+
|
2455
|
+
# :nodoc: all
|
2456
|
+
module ActiveModel::Type::Helpers::TimeValue
|
2457
|
+
def serialize: (untyped value) -> untyped
|
2458
|
+
|
2459
|
+
def apply_seconds_precision: (untyped value) -> untyped
|
2460
|
+
|
2461
|
+
def type_cast_for_schema: (untyped value) -> untyped
|
2462
|
+
|
2463
|
+
def user_input_in_time_zone: (untyped value) -> untyped
|
2464
|
+
|
2465
|
+
def new_time: (untyped year, untyped mon, untyped mday, untyped hour, untyped min, untyped sec, untyped microsec, ?untyped? offset) -> (nil | untyped)
|
2466
|
+
|
2467
|
+
# Doesn't handle time zones.
|
2468
|
+
def fast_string_to_time: (untyped string) -> untyped
|
2469
|
+
end
|
2470
|
+
|
2471
|
+
ActiveModel::Type::Helpers::TimeValue::ISO_DATETIME: untyped
|
2472
|
+
|
2473
|
+
# :nodoc: all
|
2474
|
+
module ActiveModel::Type::Helpers::Timezone
|
2475
|
+
def is_utc?: () -> untyped
|
2476
|
+
|
2477
|
+
def default_timezone: () -> untyped
|
2478
|
+
end
|
2479
|
+
|
2480
|
+
class ActiveModel::Type::ImmutableString < Value
|
2481
|
+
# :nodoc:
|
2482
|
+
def `type`: () -> :string
|
2483
|
+
|
2484
|
+
def serialize: (untyped value) -> untyped
|
2485
|
+
|
2486
|
+
def cast_value: (untyped value) -> untyped
|
2487
|
+
end
|
2488
|
+
|
2489
|
+
class ActiveModel::Type::Integer < Value
|
2490
|
+
# :nodoc:
|
2491
|
+
include Helpers::Numeric
|
2492
|
+
|
2493
|
+
def initialize: () -> untyped
|
2494
|
+
|
2495
|
+
def `type`: () -> :integer
|
2496
|
+
|
2497
|
+
def deserialize: (untyped value) -> (nil | untyped)
|
2498
|
+
|
2499
|
+
def serialize: (untyped value) -> (nil | untyped)
|
2500
|
+
|
2501
|
+
attr_reader range: untyped
|
2502
|
+
|
2503
|
+
def cast_value: (untyped value) -> untyped
|
2504
|
+
|
2505
|
+
def ensure_in_range: (untyped value) -> untyped
|
2506
|
+
|
2507
|
+
def max_value: () -> untyped
|
2508
|
+
|
2509
|
+
def min_value: () -> untyped
|
2510
|
+
|
2511
|
+
def _limit: () -> untyped
|
2512
|
+
end
|
2513
|
+
|
2514
|
+
# Column storage size in bytes.
|
2515
|
+
# 4 bytes means an integer as opposed to smallint etc.
|
2516
|
+
ActiveModel::Type::Integer::DEFAULT_LIMIT: ::Integer
|
2517
|
+
|
2518
|
+
class ActiveModel::Type::Registry
|
2519
|
+
def initialize: () -> untyped
|
2520
|
+
|
2521
|
+
def register: (untyped type_name, ?untyped? klass, **untyped options) { () -> untyped } -> untyped
|
2522
|
+
|
2523
|
+
def lookup: (untyped symbol, *untyped args, **untyped kwargs) -> untyped
|
2524
|
+
|
2525
|
+
attr_reader registrations: untyped
|
2526
|
+
|
2527
|
+
def registration_klass: () -> untyped
|
2528
|
+
|
2529
|
+
def find_registration: (untyped symbol, *untyped args) -> untyped
|
2530
|
+
end
|
2531
|
+
|
2532
|
+
class ActiveModel::Type::Registration
|
2533
|
+
# Options must be taken because of https://bugs.ruby-lang.org/issues/10856
|
2534
|
+
def initialize: (untyped name, untyped block) -> untyped
|
2535
|
+
|
2536
|
+
def call: (untyped _registry, *untyped args, **untyped kwargs) -> untyped
|
2537
|
+
|
2538
|
+
def matches?: (untyped type_name, *untyped args, **untyped kwargs) -> untyped
|
2539
|
+
|
2540
|
+
attr_reader name: untyped
|
2541
|
+
|
2542
|
+
attr_reader block: untyped
|
2543
|
+
end
|
2544
|
+
|
2545
|
+
class ActiveModel::Type::String < ImmutableString
|
2546
|
+
# :nodoc:
|
2547
|
+
def changed_in_place?: (untyped raw_old_value, untyped new_value) -> untyped
|
2548
|
+
|
2549
|
+
def cast_value: (untyped value) -> untyped
|
2550
|
+
end
|
2551
|
+
|
2552
|
+
class ActiveModel::Type::Time < Value
|
2553
|
+
# :nodoc:
|
2554
|
+
include Helpers::Timezone
|
2555
|
+
|
2556
|
+
include Helpers::TimeValue
|
2557
|
+
|
2558
|
+
def `type`: () -> :time
|
2559
|
+
|
2560
|
+
def user_input_in_time_zone: (untyped value) -> (nil | untyped)
|
2561
|
+
|
2562
|
+
def cast_value: (untyped value) -> (untyped | nil)
|
2563
|
+
end
|
2564
|
+
|
2565
|
+
class ActiveModel::Type::Value
|
2566
|
+
attr_reader precision: untyped
|
2567
|
+
|
2568
|
+
attr_reader scale: untyped
|
2569
|
+
|
2570
|
+
attr_reader limit: untyped
|
2571
|
+
|
2572
|
+
def initialize: (?scale: untyped? scale, ?limit: untyped? limit, ?precision: untyped? precision) -> untyped
|
2573
|
+
|
2574
|
+
def `type`: () -> nil
|
2575
|
+
|
2576
|
+
# Converts a value from database input to the appropriate ruby type. The
|
2577
|
+
# return value of this method will be returned from
|
2578
|
+
# ActiveRecord::AttributeMethods::Read#read_attribute. The default
|
2579
|
+
# implementation just calls Value#cast.
|
2580
|
+
#
|
2581
|
+
# +value+ The raw input, as provided from the database.
|
2582
|
+
def deserialize: (untyped value) -> untyped
|
2583
|
+
|
2584
|
+
# Type casts a value from user input (e.g. from a setter). This value may
|
2585
|
+
# be a string from the form builder, or a ruby object passed to a setter.
|
2586
|
+
# There is currently no way to differentiate between which source it came
|
2587
|
+
# from.
|
2588
|
+
#
|
2589
|
+
# The return value of this method will be returned from
|
2590
|
+
# ActiveRecord::AttributeMethods::Read#read_attribute. See also:
|
2591
|
+
# Value#cast_value.
|
2592
|
+
#
|
2593
|
+
# +value+ The raw input, as provided to the attribute setter.
|
2594
|
+
def cast: (untyped value) -> untyped
|
2595
|
+
|
2596
|
+
# Casts a value from the ruby type to a type that the database knows how
|
2597
|
+
# to understand. The returned value from this method should be a
|
2598
|
+
# +String+, +Numeric+, +Date+, +Time+, +Symbol+, +true+, +false+, or
|
2599
|
+
# +nil+.
|
2600
|
+
def serialize: (untyped value) -> untyped
|
2601
|
+
|
2602
|
+
def type_cast_for_schema: (untyped value) -> untyped
|
2603
|
+
|
2604
|
+
def binary?: () -> ::FalseClass
|
2605
|
+
|
2606
|
+
# Determines whether a value has changed for dirty checking. +old_value+
|
2607
|
+
# and +new_value+ will always be type-cast. Types should not need to
|
2608
|
+
# override this method.
|
2609
|
+
def changed?: (untyped old_value, untyped new_value, untyped _new_value_before_type_cast) -> untyped
|
2610
|
+
|
2611
|
+
# Determines whether the mutable value has been modified since it was
|
2612
|
+
# read. Returns +false+ by default. If your type returns an object
|
2613
|
+
# which could be mutated, you should override this method. You will need
|
2614
|
+
# to either:
|
2615
|
+
#
|
2616
|
+
# - pass +new_value+ to Value#serialize and compare it to
|
2617
|
+
# +raw_old_value+
|
2618
|
+
#
|
2619
|
+
# or
|
2620
|
+
#
|
2621
|
+
# - pass +raw_old_value+ to Value#deserialize and compare it to
|
2622
|
+
# +new_value+
|
2623
|
+
#
|
2624
|
+
# +raw_old_value+ The original value, before being passed to
|
2625
|
+
# +deserialize+.
|
2626
|
+
#
|
2627
|
+
# +new_value+ The current value, after type casting.
|
2628
|
+
def changed_in_place?: (untyped raw_old_value, untyped new_value) -> ::FalseClass
|
2629
|
+
|
2630
|
+
def value_constructed_by_mass_assignment?: (untyped _value) -> ::FalseClass
|
2631
|
+
|
2632
|
+
def force_equality?: (untyped _value) -> ::FalseClass
|
2633
|
+
|
2634
|
+
def map: (untyped value) { (untyped) -> untyped } -> untyped
|
2635
|
+
|
2636
|
+
def ==: (untyped other) -> untyped
|
2637
|
+
|
2638
|
+
def hash: () -> untyped
|
2639
|
+
|
2640
|
+
def assert_valid_value: () -> nil
|
2641
|
+
|
2642
|
+
def cast_value: (untyped value) -> untyped
|
2643
|
+
end
|
2644
|
+
|
2645
|
+
module ActiveModel::Validations
|
2646
|
+
extend ActiveSupport::Concern
|
2647
|
+
|
2648
|
+
extend ActiveModel::Naming
|
2649
|
+
|
2650
|
+
extend ActiveModel::Callbacks
|
2651
|
+
|
2652
|
+
extend ActiveModel::Translation
|
2653
|
+
|
2654
|
+
extend HelperMethods
|
2655
|
+
|
2656
|
+
include HelperMethods
|
2657
|
+
|
2658
|
+
attr_accessor validation_context: untyped
|
2659
|
+
|
2660
|
+
def initialize_dup: (untyped other) -> untyped
|
2661
|
+
|
2662
|
+
# Returns the +Errors+ object that holds all information about attribute
|
2663
|
+
# error messages.
|
2664
|
+
#
|
2665
|
+
# class Person
|
2666
|
+
# include ActiveModel::Validations
|
2667
|
+
#
|
2668
|
+
# attr_accessor :name
|
2669
|
+
# validates_presence_of :name
|
2670
|
+
# end
|
2671
|
+
#
|
2672
|
+
# person = Person.new
|
2673
|
+
# person.valid? # => false
|
2674
|
+
# person.errors # => #<ActiveModel::Errors:0x007fe603816640 @messages={name:["can't be blank"]}>
|
2675
|
+
def errors: () -> untyped
|
2676
|
+
|
2677
|
+
# Runs all the specified validations and returns +true+ if no errors were
|
2678
|
+
# added otherwise +false+.
|
2679
|
+
#
|
2680
|
+
# class Person
|
2681
|
+
# include ActiveModel::Validations
|
2682
|
+
#
|
2683
|
+
# attr_accessor :name
|
2684
|
+
# validates_presence_of :name
|
2685
|
+
# end
|
2686
|
+
#
|
2687
|
+
# person = Person.new
|
2688
|
+
# person.name = ''
|
2689
|
+
# person.valid? # => false
|
2690
|
+
# person.name = 'david'
|
2691
|
+
# person.valid? # => true
|
2692
|
+
#
|
2693
|
+
# Context can optionally be supplied to define which callbacks to test
|
2694
|
+
# against (the context is defined on the validations using <tt>:on</tt>).
|
2695
|
+
#
|
2696
|
+
# class Person
|
2697
|
+
# include ActiveModel::Validations
|
2698
|
+
#
|
2699
|
+
# attr_accessor :name
|
2700
|
+
# validates_presence_of :name, on: :new
|
2701
|
+
# end
|
2702
|
+
#
|
2703
|
+
# person = Person.new
|
2704
|
+
# person.valid? # => true
|
2705
|
+
# person.valid?(:new) # => false
|
2706
|
+
def valid?: (?untyped? context) -> untyped
|
2707
|
+
|
2708
|
+
# Performs the opposite of <tt>valid?</tt>. Returns +true+ if errors were
|
2709
|
+
# added, +false+ otherwise.
|
2710
|
+
#
|
2711
|
+
# class Person
|
2712
|
+
# include ActiveModel::Validations
|
2713
|
+
#
|
2714
|
+
# attr_accessor :name
|
2715
|
+
# validates_presence_of :name
|
2716
|
+
# end
|
2717
|
+
#
|
2718
|
+
# person = Person.new
|
2719
|
+
# person.name = ''
|
2720
|
+
# person.invalid? # => true
|
2721
|
+
# person.name = 'david'
|
2722
|
+
# person.invalid? # => false
|
2723
|
+
#
|
2724
|
+
# Context can optionally be supplied to define which callbacks to test
|
2725
|
+
# against (the context is defined on the validations using <tt>:on</tt>).
|
2726
|
+
#
|
2727
|
+
# class Person
|
2728
|
+
# include ActiveModel::Validations
|
2729
|
+
#
|
2730
|
+
# attr_accessor :name
|
2731
|
+
# validates_presence_of :name, on: :new
|
2732
|
+
# end
|
2733
|
+
#
|
2734
|
+
# person = Person.new
|
2735
|
+
# person.invalid? # => false
|
2736
|
+
# person.invalid?(:new) # => true
|
2737
|
+
def invalid?: (?untyped? context) -> untyped
|
2738
|
+
|
2739
|
+
# Runs all the validations within the specified context. Returns +true+ if
|
2740
|
+
# no errors are found, raises +ValidationError+ otherwise.
|
2741
|
+
#
|
2742
|
+
# Validations with no <tt>:on</tt> option will run no matter the context. Validations with
|
2743
|
+
# some <tt>:on</tt> option will only run in the specified context.
|
2744
|
+
def validate!: (?untyped? context) -> untyped
|
2745
|
+
|
2746
|
+
def run_validations!: () -> untyped
|
2747
|
+
|
2748
|
+
def raise_validation_error: () -> untyped
|
2749
|
+
|
2750
|
+
# Passes the record off to the class or classes specified and allows them
|
2751
|
+
# to add errors based on more complex conditions.
|
2752
|
+
#
|
2753
|
+
# class Person
|
2754
|
+
# include ActiveModel::Validations
|
2755
|
+
#
|
2756
|
+
# validate :instance_validations
|
2757
|
+
#
|
2758
|
+
# def instance_validations
|
2759
|
+
# validates_with MyValidator
|
2760
|
+
# end
|
2761
|
+
# end
|
2762
|
+
#
|
2763
|
+
# Please consult the class method documentation for more information on
|
2764
|
+
# creating your own validator.
|
2765
|
+
#
|
2766
|
+
# You may also pass it multiple classes, like so:
|
2767
|
+
#
|
2768
|
+
# class Person
|
2769
|
+
# include ActiveModel::Validations
|
2770
|
+
#
|
2771
|
+
# validate :instance_validations, on: :create
|
2772
|
+
#
|
2773
|
+
# def instance_validations
|
2774
|
+
# validates_with MyValidator, MyOtherValidator
|
2775
|
+
# end
|
2776
|
+
# end
|
2777
|
+
#
|
2778
|
+
# Standard configuration options (<tt>:on</tt>, <tt>:if</tt> and
|
2779
|
+
# <tt>:unless</tt>), which are available on the class version of
|
2780
|
+
# +validates_with+, should instead be placed on the +validates+ method
|
2781
|
+
# as these are applied and tested in the callback.
|
2782
|
+
#
|
2783
|
+
# If you pass any additional configuration options, they will be passed
|
2784
|
+
# to the class and available as +options+, please refer to the
|
2785
|
+
# class version of this method for more information.
|
2786
|
+
def validates_with: (*untyped args) { () -> untyped } -> untyped
|
2787
|
+
end
|
2788
|
+
|
2789
|
+
class ActiveModel::Validations::AbsenceValidator < EachValidator
|
2790
|
+
# == \Active \Model Absence Validator
|
2791
|
+
# nodoc:
|
2792
|
+
def validate_each: (untyped record, untyped attr_name, untyped value) -> untyped
|
2793
|
+
end
|
2794
|
+
|
2795
|
+
module ActiveModel::Validations::HelperMethods
|
2796
|
+
# Validates that the specified attributes are blank (as defined by
|
2797
|
+
# Object#present?). Happens by default on save.
|
2798
|
+
#
|
2799
|
+
# class Person < ActiveRecord::Base
|
2800
|
+
# validates_absence_of :first_name
|
2801
|
+
# end
|
2802
|
+
#
|
2803
|
+
# The first_name attribute must be in the object and it must be blank.
|
2804
|
+
#
|
2805
|
+
# Configuration options:
|
2806
|
+
# * <tt>:message</tt> - A custom error message (default is: "must be blank").
|
2807
|
+
#
|
2808
|
+
# There is also a list of default options supported by every validator:
|
2809
|
+
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
|
2810
|
+
# See <tt>ActiveModel::Validations#validates</tt> for more information
|
2811
|
+
def validates_absence_of: (*untyped attr_names) -> untyped
|
2812
|
+
|
2813
|
+
# Encapsulates the pattern of wanting to validate the acceptance of a
|
2814
|
+
# terms of service check box (or similar agreement).
|
2815
|
+
#
|
2816
|
+
# class Person < ActiveRecord::Base
|
2817
|
+
# validates_acceptance_of :terms_of_service
|
2818
|
+
# validates_acceptance_of :eula, message: 'must be abided'
|
2819
|
+
# end
|
2820
|
+
#
|
2821
|
+
# If the database column does not exist, the +terms_of_service+ attribute
|
2822
|
+
# is entirely virtual. This check is performed only if +terms_of_service+
|
2823
|
+
# is not +nil+ and by default on save.
|
2824
|
+
#
|
2825
|
+
# Configuration options:
|
2826
|
+
# * <tt>:message</tt> - A custom error message (default is: "must be
|
2827
|
+
# accepted").
|
2828
|
+
# * <tt>:accept</tt> - Specifies a value that is considered accepted.
|
2829
|
+
# Also accepts an array of possible values. The default value is
|
2830
|
+
# an array ["1", true], which makes it easy to relate to an HTML
|
2831
|
+
# checkbox. This should be set to, or include, +true+ if you are validating
|
2832
|
+
# a database column, since the attribute is typecast from "1" to +true+
|
2833
|
+
# before validation.
|
2834
|
+
#
|
2835
|
+
# There is also a list of default options supported by every validator:
|
2836
|
+
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
|
2837
|
+
# See <tt>ActiveModel::Validations#validates</tt> for more information.
|
2838
|
+
def validates_acceptance_of: (*untyped attr_names) -> untyped
|
2839
|
+
|
2840
|
+
# Encapsulates the pattern of wanting to validate a password or email
|
2841
|
+
# address field with a confirmation.
|
2842
|
+
#
|
2843
|
+
# Model:
|
2844
|
+
# class Person < ActiveRecord::Base
|
2845
|
+
# validates_confirmation_of :user_name, :password
|
2846
|
+
# validates_confirmation_of :email_address,
|
2847
|
+
# message: 'should match confirmation'
|
2848
|
+
# end
|
2849
|
+
#
|
2850
|
+
# View:
|
2851
|
+
# <%= password_field "person", "password" %>
|
2852
|
+
# <%= password_field "person", "password_confirmation" %>
|
2853
|
+
#
|
2854
|
+
# The added +password_confirmation+ attribute is virtual; it exists only
|
2855
|
+
# as an in-memory attribute for validating the password. To achieve this,
|
2856
|
+
# the validation adds accessors to the model for the confirmation
|
2857
|
+
# attribute.
|
2858
|
+
#
|
2859
|
+
# NOTE: This check is performed only if +password_confirmation+ is not
|
2860
|
+
# +nil+. To require confirmation, make sure to add a presence check for
|
2861
|
+
# the confirmation attribute:
|
2862
|
+
#
|
2863
|
+
# validates_presence_of :password_confirmation, if: :password_changed?
|
2864
|
+
#
|
2865
|
+
# Configuration options:
|
2866
|
+
# * <tt>:message</tt> - A custom error message (default is: "doesn't match
|
2867
|
+
# <tt>%{translated_attribute_name}</tt>").
|
2868
|
+
# * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by
|
2869
|
+
# non-text columns (+true+ by default).
|
2870
|
+
#
|
2871
|
+
# There is also a list of default options supported by every validator:
|
2872
|
+
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
|
2873
|
+
# See <tt>ActiveModel::Validations#validates</tt> for more information
|
2874
|
+
def validates_confirmation_of: (*untyped attr_names) -> untyped
|
2875
|
+
|
2876
|
+
# Validates that the value of the specified attribute is not in a
|
2877
|
+
# particular enumerable object.
|
2878
|
+
#
|
2879
|
+
# class Person < ActiveRecord::Base
|
2880
|
+
# validates_exclusion_of :username, in: %w( admin superuser ), message: "You don't belong here"
|
2881
|
+
# validates_exclusion_of :age, in: 30..60, message: 'This site is only for under 30 and over 60'
|
2882
|
+
# validates_exclusion_of :format, in: %w( mov avi ), message: "extension %{value} is not allowed"
|
2883
|
+
# validates_exclusion_of :password, in: ->(person) { [person.username, person.first_name] },
|
2884
|
+
# message: 'should not be the same as your username or first name'
|
2885
|
+
# validates_exclusion_of :karma, in: :reserved_karmas
|
2886
|
+
# end
|
2887
|
+
#
|
2888
|
+
# Configuration options:
|
2889
|
+
# * <tt>:in</tt> - An enumerable object of items that the value shouldn't
|
2890
|
+
# be part of. This can be supplied as a proc, lambda or symbol which returns an
|
2891
|
+
# enumerable. If the enumerable is a numerical, time or datetime range the test
|
2892
|
+
# is performed with <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>. When
|
2893
|
+
# using a proc or lambda the instance under validation is passed as an argument.
|
2894
|
+
# * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
|
2895
|
+
# <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>.
|
2896
|
+
# * <tt>:message</tt> - Specifies a custom error message (default is: "is
|
2897
|
+
# reserved").
|
2898
|
+
#
|
2899
|
+
# There is also a list of default options supported by every validator:
|
2900
|
+
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
|
2901
|
+
# See <tt>ActiveModel::Validations#validates</tt> for more information
|
2902
|
+
def validates_exclusion_of: (*untyped attr_names) -> untyped
|
2903
|
+
|
2904
|
+
# Validates whether the value of the specified attribute is of the correct
|
2905
|
+
# form, going by the regular expression provided. You can require that the
|
2906
|
+
# attribute matches the regular expression:
|
2907
|
+
#
|
2908
|
+
# class Person < ActiveRecord::Base
|
2909
|
+
# validates_format_of :email, with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create
|
2910
|
+
# end
|
2911
|
+
#
|
2912
|
+
# Alternatively, you can require that the specified attribute does _not_
|
2913
|
+
# match the regular expression:
|
2914
|
+
#
|
2915
|
+
# class Person < ActiveRecord::Base
|
2916
|
+
# validates_format_of :email, without: /NOSPAM/
|
2917
|
+
# end
|
2918
|
+
#
|
2919
|
+
# You can also provide a proc or lambda which will determine the regular
|
2920
|
+
# expression that will be used to validate the attribute.
|
2921
|
+
#
|
2922
|
+
# class Person < ActiveRecord::Base
|
2923
|
+
# # Admin can have number as a first letter in their screen name
|
2924
|
+
# validates_format_of :screen_name,
|
2925
|
+
# with: ->(person) { person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\z/i : /\A[a-z][a-z0-9_\-]*\z/i }
|
2926
|
+
# end
|
2927
|
+
#
|
2928
|
+
# Note: use <tt>\A</tt> and <tt>\z</tt> to match the start and end of the
|
2929
|
+
# string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
|
2930
|
+
#
|
2931
|
+
# Due to frequent misuse of <tt>^</tt> and <tt>$</tt>, you need to pass
|
2932
|
+
# the <tt>multiline: true</tt> option in case you use any of these two
|
2933
|
+
# anchors in the provided regular expression. In most cases, you should be
|
2934
|
+
# using <tt>\A</tt> and <tt>\z</tt>.
|
2935
|
+
#
|
2936
|
+
# You must pass either <tt>:with</tt> or <tt>:without</tt> as an option.
|
2937
|
+
# In addition, both must be a regular expression or a proc or lambda, or
|
2938
|
+
# else an exception will be raised.
|
2939
|
+
#
|
2940
|
+
# Configuration options:
|
2941
|
+
# * <tt>:message</tt> - A custom error message (default is: "is invalid").
|
2942
|
+
# * <tt>:with</tt> - Regular expression that if the attribute matches will
|
2943
|
+
# result in a successful validation. This can be provided as a proc or
|
2944
|
+
# lambda returning regular expression which will be called at runtime.
|
2945
|
+
# * <tt>:without</tt> - Regular expression that if the attribute does not
|
2946
|
+
# match will result in a successful validation. This can be provided as
|
2947
|
+
# a proc or lambda returning regular expression which will be called at
|
2948
|
+
# runtime.
|
2949
|
+
# * <tt>:multiline</tt> - Set to true if your regular expression contains
|
2950
|
+
# anchors that match the beginning or end of lines as opposed to the
|
2951
|
+
# beginning or end of the string. These anchors are <tt>^</tt> and <tt>$</tt>.
|
2952
|
+
#
|
2953
|
+
# There is also a list of default options supported by every validator:
|
2954
|
+
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
|
2955
|
+
# See <tt>ActiveModel::Validations#validates</tt> for more information
|
2956
|
+
def validates_format_of: (*untyped attr_names) -> untyped
|
2957
|
+
|
2958
|
+
def _merge_attributes: (untyped attr_names) -> untyped
|
2959
|
+
|
2960
|
+
# Validates whether the value of the specified attribute is available in a
|
2961
|
+
# particular enumerable object.
|
2962
|
+
#
|
2963
|
+
# class Person < ActiveRecord::Base
|
2964
|
+
# validates_inclusion_of :role, in: %w( admin contributor )
|
2965
|
+
# validates_inclusion_of :age, in: 0..99
|
2966
|
+
# validates_inclusion_of :format, in: %w( jpg gif png ), message: "extension %{value} is not included in the list"
|
2967
|
+
# validates_inclusion_of :states, in: ->(person) { STATES[person.country] }
|
2968
|
+
# validates_inclusion_of :karma, in: :available_karmas
|
2969
|
+
# end
|
2970
|
+
#
|
2971
|
+
# Configuration options:
|
2972
|
+
# * <tt>:in</tt> - An enumerable object of available items. This can be
|
2973
|
+
# supplied as a proc, lambda or symbol which returns an enumerable. If the
|
2974
|
+
# enumerable is a numerical, time or datetime range the test is performed
|
2975
|
+
# with <tt>Range#cover?</tt>, otherwise with <tt>include?</tt>. When using
|
2976
|
+
# a proc or lambda the instance under validation is passed as an argument.
|
2977
|
+
# * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
|
2978
|
+
# * <tt>:message</tt> - Specifies a custom error message (default is: "is
|
2979
|
+
# not included in the list").
|
2980
|
+
#
|
2981
|
+
# There is also a list of default options supported by every validator:
|
2982
|
+
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
|
2983
|
+
# See <tt>ActiveModel::Validations#validates</tt> for more information
|
2984
|
+
def validates_inclusion_of: (*untyped attr_names) -> untyped
|
2985
|
+
|
2986
|
+
# Validates that the specified attributes match the length restrictions
|
2987
|
+
# supplied. Only one constraint option can be used at a time apart from
|
2988
|
+
# +:minimum+ and +:maximum+ that can be combined together:
|
2989
|
+
#
|
2990
|
+
# class Person < ActiveRecord::Base
|
2991
|
+
# validates_length_of :first_name, maximum: 30
|
2992
|
+
# validates_length_of :last_name, maximum: 30, message: "less than 30 if you don't mind"
|
2993
|
+
# validates_length_of :fax, in: 7..32, allow_nil: true
|
2994
|
+
# validates_length_of :phone, in: 7..32, allow_blank: true
|
2995
|
+
# validates_length_of :user_name, within: 6..20, too_long: 'pick a shorter name', too_short: 'pick a longer name'
|
2996
|
+
# validates_length_of :zip_code, minimum: 5, too_short: 'please enter at least 5 characters'
|
2997
|
+
# validates_length_of :smurf_leader, is: 4, message: "papa is spelled with 4 characters... don't play me."
|
2998
|
+
# validates_length_of :words_in_essay, minimum: 100, too_short: 'Your essay must be at least 100 words.'
|
2999
|
+
#
|
3000
|
+
# private
|
3001
|
+
#
|
3002
|
+
# def words_in_essay
|
3003
|
+
# essay.scan(/\w+/)
|
3004
|
+
# end
|
3005
|
+
# end
|
3006
|
+
#
|
3007
|
+
# Constraint options:
|
3008
|
+
#
|
3009
|
+
# * <tt>:minimum</tt> - The minimum size of the attribute.
|
3010
|
+
# * <tt>:maximum</tt> - The maximum size of the attribute. Allows +nil+ by
|
3011
|
+
# default if not used with +:minimum+.
|
3012
|
+
# * <tt>:is</tt> - The exact size of the attribute.
|
3013
|
+
# * <tt>:within</tt> - A range specifying the minimum and maximum size of
|
3014
|
+
# the attribute.
|
3015
|
+
# * <tt>:in</tt> - A synonym (or alias) for <tt>:within</tt>.
|
3016
|
+
#
|
3017
|
+
# Other options:
|
3018
|
+
#
|
3019
|
+
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
|
3020
|
+
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
|
3021
|
+
# * <tt>:too_long</tt> - The error message if the attribute goes over the
|
3022
|
+
# maximum (default is: "is too long (maximum is %{count} characters)").
|
3023
|
+
# * <tt>:too_short</tt> - The error message if the attribute goes under the
|
3024
|
+
# minimum (default is: "is too short (minimum is %{count} characters)").
|
3025
|
+
# * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt>
|
3026
|
+
# method and the attribute is the wrong size (default is: "is the wrong
|
3027
|
+
# length (should be %{count} characters)").
|
3028
|
+
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>,
|
3029
|
+
# <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate
|
3030
|
+
# <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
|
3031
|
+
#
|
3032
|
+
# There is also a list of default options supported by every validator:
|
3033
|
+
# +:if+, +:unless+, +:on+ and +:strict+.
|
3034
|
+
# See <tt>ActiveModel::Validations#validates</tt> for more information
|
3035
|
+
def validates_length_of: (*untyped attr_names) -> untyped
|
3036
|
+
|
3037
|
+
# Validates whether the value of the specified attribute is numeric by
|
3038
|
+
# trying to convert it to a float with Kernel.Float (if <tt>only_integer</tt>
|
3039
|
+
# is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\z/</tt>
|
3040
|
+
# (if <tt>only_integer</tt> is set to +true+).
|
3041
|
+
#
|
3042
|
+
# class Person < ActiveRecord::Base
|
3043
|
+
# validates_numericality_of :value, on: :create
|
3044
|
+
# end
|
3045
|
+
#
|
3046
|
+
# Configuration options:
|
3047
|
+
# * <tt>:message</tt> - A custom error message (default is: "is not a number").
|
3048
|
+
# * <tt>:only_integer</tt> - Specifies whether the value has to be an
|
3049
|
+
# integer, e.g. an integral value (default is +false+).
|
3050
|
+
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is
|
3051
|
+
# +false+). Notice that for Integer and Float columns empty strings are
|
3052
|
+
# converted to +nil+.
|
3053
|
+
# * <tt>:greater_than</tt> - Specifies the value must be greater than the
|
3054
|
+
# supplied value.
|
3055
|
+
# * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be
|
3056
|
+
# greater than or equal the supplied value.
|
3057
|
+
# * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied
|
3058
|
+
# value.
|
3059
|
+
# * <tt>:less_than</tt> - Specifies the value must be less than the
|
3060
|
+
# supplied value.
|
3061
|
+
# * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less
|
3062
|
+
# than or equal the supplied value.
|
3063
|
+
# * <tt>:other_than</tt> - Specifies the value must be other than the
|
3064
|
+
# supplied value.
|
3065
|
+
# * <tt>:odd</tt> - Specifies the value must be an odd number.
|
3066
|
+
# * <tt>:even</tt> - Specifies the value must be an even number.
|
3067
|
+
#
|
3068
|
+
# There is also a list of default options supported by every validator:
|
3069
|
+
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+ .
|
3070
|
+
# See <tt>ActiveModel::Validations#validates</tt> for more information
|
3071
|
+
#
|
3072
|
+
# The following checks can also be supplied with a proc or a symbol which
|
3073
|
+
# corresponds to a method:
|
3074
|
+
#
|
3075
|
+
# * <tt>:greater_than</tt>
|
3076
|
+
# * <tt>:greater_than_or_equal_to</tt>
|
3077
|
+
# * <tt>:equal_to</tt>
|
3078
|
+
# * <tt>:less_than</tt>
|
3079
|
+
# * <tt>:less_than_or_equal_to</tt>
|
3080
|
+
# * <tt>:only_integer</tt>
|
3081
|
+
#
|
3082
|
+
# For example:
|
3083
|
+
#
|
3084
|
+
# class Person < ActiveRecord::Base
|
3085
|
+
# validates_numericality_of :width, less_than: ->(person) { person.height }
|
3086
|
+
# validates_numericality_of :width, greater_than: :minimum_weight
|
3087
|
+
# end
|
3088
|
+
def validates_numericality_of: (*untyped attr_names) -> untyped
|
3089
|
+
|
3090
|
+
# Validates that the specified attributes are not blank (as defined by
|
3091
|
+
# Object#blank?). Happens by default on save.
|
3092
|
+
#
|
3093
|
+
# class Person < ActiveRecord::Base
|
3094
|
+
# validates_presence_of :first_name
|
3095
|
+
# end
|
3096
|
+
#
|
3097
|
+
# The first_name attribute must be in the object and it cannot be blank.
|
3098
|
+
#
|
3099
|
+
# If you want to validate the presence of a boolean field (where the real
|
3100
|
+
# values are +true+ and +false+), you will want to use
|
3101
|
+
# <tt>validates_inclusion_of :field_name, in: [true, false]</tt>.
|
3102
|
+
#
|
3103
|
+
# This is due to the way Object#blank? handles boolean values:
|
3104
|
+
# <tt>false.blank? # => true</tt>.
|
3105
|
+
#
|
3106
|
+
# Configuration options:
|
3107
|
+
# * <tt>:message</tt> - A custom error message (default is: "can't be blank").
|
3108
|
+
#
|
3109
|
+
# There is also a list of default options supported by every validator:
|
3110
|
+
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
|
3111
|
+
# See <tt>ActiveModel::Validations#validates</tt> for more information
|
3112
|
+
def validates_presence_of: (*untyped attr_names) -> untyped
|
3113
|
+
end
|
3114
|
+
|
3115
|
+
class ActiveModel::Validations::AcceptanceValidator < EachValidator
|
3116
|
+
# :nodoc:
|
3117
|
+
def initialize: (untyped options) -> untyped
|
3118
|
+
|
3119
|
+
def validate_each: (untyped record, untyped attribute, untyped value) -> untyped
|
3120
|
+
|
3121
|
+
def setup!: (untyped klass) -> untyped
|
3122
|
+
|
3123
|
+
def acceptable_option?: (untyped value) -> untyped
|
3124
|
+
end
|
3125
|
+
|
3126
|
+
class ActiveModel::Validations::AcceptanceValidator::LazilyDefineAttributes < Module
|
3127
|
+
def initialize: (untyped attributes) -> untyped
|
3128
|
+
|
3129
|
+
def included: (untyped klass) -> untyped
|
3130
|
+
|
3131
|
+
def matches?: (untyped method_name) -> untyped
|
3132
|
+
|
3133
|
+
def define_on: (untyped klass) -> untyped
|
3134
|
+
|
3135
|
+
def ==: (untyped other) -> untyped
|
3136
|
+
|
3137
|
+
attr_reader attributes: untyped
|
3138
|
+
end
|
3139
|
+
|
3140
|
+
# == Active \Model \Validation \Callbacks
|
3141
|
+
#
|
3142
|
+
# Provides an interface for any class to have +before_validation+ and
|
3143
|
+
# +after_validation+ callbacks.
|
3144
|
+
#
|
3145
|
+
# First, include ActiveModel::Validations::Callbacks from the class you are
|
3146
|
+
# creating:
|
3147
|
+
#
|
3148
|
+
# class MyModel
|
3149
|
+
# include ActiveModel::Validations::Callbacks
|
3150
|
+
#
|
3151
|
+
# before_validation :do_stuff_before_validation
|
3152
|
+
# after_validation :do_stuff_after_validation
|
3153
|
+
# end
|
3154
|
+
#
|
3155
|
+
# Like other <tt>before_*</tt> callbacks if +before_validation+ throws
|
3156
|
+
# +:abort+ then <tt>valid?</tt> will not be called.
|
3157
|
+
module ActiveModel::Validations::Callbacks
|
3158
|
+
extend ActiveSupport::Concern
|
3159
|
+
|
3160
|
+
include ActiveSupport::Callbacks
|
3161
|
+
|
3162
|
+
# Overwrite run validations to include callbacks.
|
3163
|
+
def run_validations!: () -> untyped
|
3164
|
+
end
|
3165
|
+
|
3166
|
+
module ActiveModel::Validations::Callbacks::ClassMethods
|
3167
|
+
# Defines a callback that will get called right before validation.
|
3168
|
+
#
|
3169
|
+
# class Person
|
3170
|
+
# include ActiveModel::Validations
|
3171
|
+
# include ActiveModel::Validations::Callbacks
|
3172
|
+
#
|
3173
|
+
# attr_accessor :name
|
3174
|
+
#
|
3175
|
+
# validates_length_of :name, maximum: 6
|
3176
|
+
#
|
3177
|
+
# before_validation :remove_whitespaces
|
3178
|
+
#
|
3179
|
+
# private
|
3180
|
+
#
|
3181
|
+
# def remove_whitespaces
|
3182
|
+
# name.strip!
|
3183
|
+
# end
|
3184
|
+
# end
|
3185
|
+
#
|
3186
|
+
# person = Person.new
|
3187
|
+
# person.name = ' bob '
|
3188
|
+
# person.valid? # => true
|
3189
|
+
# person.name # => "bob"
|
3190
|
+
def before_validation: (*untyped args) { () -> untyped } -> untyped
|
3191
|
+
|
3192
|
+
# Defines a callback that will get called right after validation.
|
3193
|
+
#
|
3194
|
+
# class Person
|
3195
|
+
# include ActiveModel::Validations
|
3196
|
+
# include ActiveModel::Validations::Callbacks
|
3197
|
+
#
|
3198
|
+
# attr_accessor :name, :status
|
3199
|
+
#
|
3200
|
+
# validates_presence_of :name
|
3201
|
+
#
|
3202
|
+
# after_validation :set_status
|
3203
|
+
#
|
3204
|
+
# private
|
3205
|
+
#
|
3206
|
+
# def set_status
|
3207
|
+
# self.status = errors.empty?
|
3208
|
+
# end
|
3209
|
+
# end
|
3210
|
+
#
|
3211
|
+
# person = Person.new
|
3212
|
+
# person.name = ''
|
3213
|
+
# person.valid? # => false
|
3214
|
+
# person.status # => false
|
3215
|
+
# person.name = 'bob'
|
3216
|
+
# person.valid? # => true
|
3217
|
+
# person.status # => true
|
3218
|
+
def after_validation: (*untyped args) { () -> untyped } -> untyped
|
3219
|
+
end
|
3220
|
+
|
3221
|
+
module ActiveModel::Validations::Clusivity
|
3222
|
+
def check_validity!: () -> untyped
|
3223
|
+
|
3224
|
+
def include?: (untyped record, untyped value) -> untyped
|
3225
|
+
|
3226
|
+
def delimiter: () -> untyped
|
3227
|
+
|
3228
|
+
# After Ruby 2.2, <tt>Range#include?</tt> on non-number-or-time-ish ranges checks all
|
3229
|
+
# possible values in the range for equality, which is slower but more accurate.
|
3230
|
+
# <tt>Range#cover?</tt> uses the previous logic of comparing a value with the range
|
3231
|
+
# endpoints, which is fast but is only accurate on Numeric, Time, Date,
|
3232
|
+
# or DateTime ranges.
|
3233
|
+
def inclusion_method: (untyped enumerable) -> untyped
|
3234
|
+
end
|
3235
|
+
|
3236
|
+
# nodoc:
|
3237
|
+
ActiveModel::Validations::Clusivity::ERROR_MESSAGE: ::String
|
3238
|
+
|
3239
|
+
class ActiveModel::Validations::ConfirmationValidator < EachValidator
|
3240
|
+
# :nodoc:
|
3241
|
+
def initialize: (untyped options) -> untyped
|
3242
|
+
|
3243
|
+
def validate_each: (untyped record, untyped attribute, untyped value) -> untyped
|
3244
|
+
|
3245
|
+
def setup!: (untyped klass) -> untyped
|
3246
|
+
|
3247
|
+
def confirmation_value_equal?: (untyped record, untyped attribute, untyped value, untyped confirmed) -> untyped
|
3248
|
+
end
|
3249
|
+
|
3250
|
+
class ActiveModel::Validations::ExclusionValidator < EachValidator
|
3251
|
+
# :nodoc:
|
3252
|
+
include Clusivity
|
3253
|
+
|
3254
|
+
def validate_each: (untyped record, untyped attribute, untyped value) -> untyped
|
3255
|
+
end
|
3256
|
+
|
3257
|
+
class ActiveModel::Validations::FormatValidator < EachValidator
|
3258
|
+
# :nodoc:
|
3259
|
+
def validate_each: (untyped record, untyped attribute, untyped value) -> untyped
|
3260
|
+
|
3261
|
+
def check_validity!: () -> untyped
|
3262
|
+
|
3263
|
+
def option_call: (untyped record, untyped name) -> untyped
|
3264
|
+
|
3265
|
+
def record_error: (untyped record, untyped attribute, untyped name, untyped value) -> untyped
|
3266
|
+
|
3267
|
+
def check_options_validity: (untyped name) -> untyped
|
3268
|
+
|
3269
|
+
def regexp_using_multiline_anchors?: (untyped regexp) -> untyped
|
3270
|
+
end
|
3271
|
+
|
3272
|
+
class ActiveModel::Validations::InclusionValidator < EachValidator
|
3273
|
+
# :nodoc:
|
3274
|
+
include Clusivity
|
3275
|
+
|
3276
|
+
def validate_each: (untyped record, untyped attribute, untyped value) -> untyped
|
3277
|
+
end
|
3278
|
+
|
3279
|
+
class ActiveModel::Validations::LengthValidator < EachValidator
|
3280
|
+
def initialize: (untyped options) -> untyped
|
3281
|
+
|
3282
|
+
def check_validity!: () -> untyped
|
3283
|
+
|
3284
|
+
def validate_each: (untyped record, untyped attribute, untyped value) -> untyped
|
3285
|
+
|
3286
|
+
def skip_nil_check?: (untyped key) -> untyped
|
3287
|
+
end
|
3288
|
+
|
3289
|
+
# :nodoc:
|
3290
|
+
ActiveModel::Validations::LengthValidator::MESSAGES: untyped
|
3291
|
+
|
3292
|
+
ActiveModel::Validations::LengthValidator::CHECKS: untyped
|
3293
|
+
|
3294
|
+
ActiveModel::Validations::LengthValidator::RESERVED_OPTIONS: ::Array[untyped]
|
3295
|
+
|
3296
|
+
class ActiveModel::Validations::NumericalityValidator < EachValidator
|
3297
|
+
def check_validity!: () -> untyped
|
3298
|
+
|
3299
|
+
def validate_each: (untyped record, untyped attr_name, untyped value) -> (nil | untyped)
|
3300
|
+
|
3301
|
+
def is_number?: (untyped raw_value) -> untyped
|
3302
|
+
|
3303
|
+
def parse_as_number: (untyped raw_value) -> untyped
|
3304
|
+
|
3305
|
+
def is_integer?: (untyped raw_value) -> untyped
|
3306
|
+
|
3307
|
+
def is_hexadecimal_literal?: (untyped raw_value) -> untyped
|
3308
|
+
|
3309
|
+
def filtered_options: (untyped value) -> untyped
|
3310
|
+
|
3311
|
+
def allow_only_integer?: (untyped record) -> untyped
|
3312
|
+
|
3313
|
+
def record_attribute_changed_in_place?: (untyped record, untyped attr_name) -> untyped
|
3314
|
+
end
|
3315
|
+
|
3316
|
+
# :nodoc:
|
3317
|
+
ActiveModel::Validations::NumericalityValidator::CHECKS: untyped
|
3318
|
+
|
3319
|
+
ActiveModel::Validations::NumericalityValidator::RESERVED_OPTIONS: untyped
|
3320
|
+
|
3321
|
+
ActiveModel::Validations::NumericalityValidator::INTEGER_REGEX: untyped
|
3322
|
+
|
3323
|
+
ActiveModel::Validations::NumericalityValidator::HEXADECIMAL_REGEX: untyped
|
3324
|
+
|
3325
|
+
class ActiveModel::Validations::PresenceValidator < EachValidator
|
3326
|
+
# :nodoc:
|
3327
|
+
def validate_each: (untyped record, untyped attr_name, untyped value) -> untyped
|
3328
|
+
end
|
3329
|
+
|
3330
|
+
module ActiveModel::Validations::ClassMethods
|
3331
|
+
# Validates each attribute against a block.
|
3332
|
+
#
|
3333
|
+
# class Person
|
3334
|
+
# include ActiveModel::Validations
|
3335
|
+
#
|
3336
|
+
# attr_accessor :first_name, :last_name
|
3337
|
+
#
|
3338
|
+
# validates_each :first_name, :last_name, allow_blank: true do |record, attr, value|
|
3339
|
+
# record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
|
3340
|
+
# end
|
3341
|
+
# end
|
3342
|
+
#
|
3343
|
+
# Options:
|
3344
|
+
# * <tt>:on</tt> - Specifies the contexts where this validation is active.
|
3345
|
+
# Runs in all validation contexts by default +nil+. You can pass a symbol
|
3346
|
+
# or an array of symbols. (e.g. <tt>on: :create</tt> or
|
3347
|
+
# <tt>on: :custom_validation_context</tt> or
|
3348
|
+
# <tt>on: [:create, :custom_validation_context]</tt>)
|
3349
|
+
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
|
3350
|
+
# * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
|
3351
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
3352
|
+
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
|
3353
|
+
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
|
3354
|
+
# proc or string should return or evaluate to a +true+ or +false+ value.
|
3355
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
|
3356
|
+
# determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
|
3357
|
+
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
3358
|
+
# method, proc or string should return or evaluate to a +true+ or +false+
|
3359
|
+
# value.
|
3360
|
+
def validates_each: (*untyped attr_names) { () -> untyped } -> untyped
|
3361
|
+
|
3362
|
+
# Adds a validation method or block to the class. This is useful when
|
3363
|
+
# overriding the +validate+ instance method becomes too unwieldy and
|
3364
|
+
# you're looking for more descriptive declaration of your validations.
|
3365
|
+
#
|
3366
|
+
# This can be done with a symbol pointing to a method:
|
3367
|
+
#
|
3368
|
+
# class Comment
|
3369
|
+
# include ActiveModel::Validations
|
3370
|
+
#
|
3371
|
+
# validate :must_be_friends
|
3372
|
+
#
|
3373
|
+
# def must_be_friends
|
3374
|
+
# errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
|
3375
|
+
# end
|
3376
|
+
# end
|
3377
|
+
#
|
3378
|
+
# With a block which is passed with the current record to be validated:
|
3379
|
+
#
|
3380
|
+
# class Comment
|
3381
|
+
# include ActiveModel::Validations
|
3382
|
+
#
|
3383
|
+
# validate do |comment|
|
3384
|
+
# comment.must_be_friends
|
3385
|
+
# end
|
3386
|
+
#
|
3387
|
+
# def must_be_friends
|
3388
|
+
# errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
|
3389
|
+
# end
|
3390
|
+
# end
|
3391
|
+
#
|
3392
|
+
# Or with a block where self points to the current record to be validated:
|
3393
|
+
#
|
3394
|
+
# class Comment
|
3395
|
+
# include ActiveModel::Validations
|
3396
|
+
#
|
3397
|
+
# validate do
|
3398
|
+
# errors.add(:base, 'Must be friends to leave a comment') unless commenter.friend_of?(commentee)
|
3399
|
+
# end
|
3400
|
+
# end
|
3401
|
+
#
|
3402
|
+
# Note that the return value of validation methods is not relevant.
|
3403
|
+
# It's not possible to halt the validate callback chain.
|
3404
|
+
#
|
3405
|
+
# Options:
|
3406
|
+
# * <tt>:on</tt> - Specifies the contexts where this validation is active.
|
3407
|
+
# Runs in all validation contexts by default +nil+. You can pass a symbol
|
3408
|
+
# or an array of symbols. (e.g. <tt>on: :create</tt> or
|
3409
|
+
# <tt>on: :custom_validation_context</tt> or
|
3410
|
+
# <tt>on: [:create, :custom_validation_context]</tt>)
|
3411
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
3412
|
+
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
|
3413
|
+
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
|
3414
|
+
# proc or string should return or evaluate to a +true+ or +false+ value.
|
3415
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
|
3416
|
+
# determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
|
3417
|
+
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
3418
|
+
# method, proc or string should return or evaluate to a +true+ or +false+
|
3419
|
+
# value.
|
3420
|
+
#
|
3421
|
+
# NOTE: Calling +validate+ multiple times on the same method will overwrite previous definitions.
|
3422
|
+
#
|
3423
|
+
def validate: (*untyped args) { () -> untyped } -> untyped
|
3424
|
+
|
3425
|
+
# List all validators that are being used to validate the model using
|
3426
|
+
# +validates_with+ method.
|
3427
|
+
#
|
3428
|
+
# class Person
|
3429
|
+
# include ActiveModel::Validations
|
3430
|
+
#
|
3431
|
+
# validates_with MyValidator
|
3432
|
+
# validates_with OtherValidator, on: :create
|
3433
|
+
# validates_with StrictValidator, strict: true
|
3434
|
+
# end
|
3435
|
+
#
|
3436
|
+
# Person.validators
|
3437
|
+
# # => [
|
3438
|
+
# # #<MyValidator:0x007fbff403e808 @options={}>,
|
3439
|
+
# # #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
|
3440
|
+
# # #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
|
3441
|
+
# # ]
|
3442
|
+
def validators: () -> untyped
|
3443
|
+
|
3444
|
+
# Clears all of the validators and validations.
|
3445
|
+
#
|
3446
|
+
# Note that this will clear anything that is being used to validate
|
3447
|
+
# the model for both the +validates_with+ and +validate+ methods.
|
3448
|
+
# It clears the validators that are created with an invocation of
|
3449
|
+
# +validates_with+ and the callbacks that are set by an invocation
|
3450
|
+
# of +validate+.
|
3451
|
+
#
|
3452
|
+
# class Person
|
3453
|
+
# include ActiveModel::Validations
|
3454
|
+
#
|
3455
|
+
# validates_with MyValidator
|
3456
|
+
# validates_with OtherValidator, on: :create
|
3457
|
+
# validates_with StrictValidator, strict: true
|
3458
|
+
# validate :cannot_be_robot
|
3459
|
+
#
|
3460
|
+
# def cannot_be_robot
|
3461
|
+
# errors.add(:base, 'A person cannot be a robot') if person_is_robot
|
3462
|
+
# end
|
3463
|
+
# end
|
3464
|
+
#
|
3465
|
+
# Person.validators
|
3466
|
+
# # => [
|
3467
|
+
# # #<MyValidator:0x007fbff403e808 @options={}>,
|
3468
|
+
# # #<OtherValidator:0x007fbff403d930 @options={on: :create}>,
|
3469
|
+
# # #<StrictValidator:0x007fbff3204a30 @options={strict:true}>
|
3470
|
+
# # ]
|
3471
|
+
#
|
3472
|
+
# If one runs <tt>Person.clear_validators!</tt> and then checks to see what
|
3473
|
+
# validators this class has, you would obtain:
|
3474
|
+
#
|
3475
|
+
# Person.validators # => []
|
3476
|
+
#
|
3477
|
+
# Also, the callback set by <tt>validate :cannot_be_robot</tt> will be erased
|
3478
|
+
# so that:
|
3479
|
+
#
|
3480
|
+
# Person._validate_callbacks.empty? # => true
|
3481
|
+
#
|
3482
|
+
def clear_validators!: () -> untyped
|
3483
|
+
|
3484
|
+
# List all validators that are being used to validate a specific attribute.
|
3485
|
+
#
|
3486
|
+
# class Person
|
3487
|
+
# include ActiveModel::Validations
|
3488
|
+
#
|
3489
|
+
# attr_accessor :name , :age
|
3490
|
+
#
|
3491
|
+
# validates_presence_of :name
|
3492
|
+
# validates_inclusion_of :age, in: 0..99
|
3493
|
+
# end
|
3494
|
+
#
|
3495
|
+
# Person.validators_on(:name)
|
3496
|
+
# # => [
|
3497
|
+
# # #<ActiveModel::Validations::PresenceValidator:0x007fe604914e60 @attributes=[:name], @options={}>,
|
3498
|
+
# # ]
|
3499
|
+
def validators_on: (*untyped attributes) -> untyped
|
3500
|
+
|
3501
|
+
# Returns +true+ if +attribute+ is an attribute method, +false+ otherwise.
|
3502
|
+
#
|
3503
|
+
# class Person
|
3504
|
+
# include ActiveModel::Validations
|
3505
|
+
#
|
3506
|
+
# attr_accessor :name
|
3507
|
+
# end
|
3508
|
+
#
|
3509
|
+
# User.attribute_method?(:name) # => true
|
3510
|
+
# User.attribute_method?(:age) # => false
|
3511
|
+
def attribute_method?: (untyped attribute) -> untyped
|
3512
|
+
|
3513
|
+
def inherited: (untyped base) -> untyped
|
3514
|
+
|
3515
|
+
# This method is a shortcut to all default validators and any custom
|
3516
|
+
# validator classes ending in 'Validator'. Note that Rails default
|
3517
|
+
# validators can be overridden inside specific classes by creating
|
3518
|
+
# custom validator classes in their place such as PresenceValidator.
|
3519
|
+
#
|
3520
|
+
# Examples of using the default rails validators:
|
3521
|
+
#
|
3522
|
+
# validates :terms, acceptance: true
|
3523
|
+
# validates :password, confirmation: true
|
3524
|
+
# validates :username, exclusion: { in: %w(admin superuser) }
|
3525
|
+
# validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
|
3526
|
+
# validates :age, inclusion: { in: 0..9 }
|
3527
|
+
# validates :first_name, length: { maximum: 30 }
|
3528
|
+
# validates :age, numericality: true
|
3529
|
+
# validates :username, presence: true
|
3530
|
+
#
|
3531
|
+
# The power of the +validates+ method comes when using custom validators
|
3532
|
+
# and default validators in one call for a given attribute.
|
3533
|
+
#
|
3534
|
+
# class EmailValidator < ActiveModel::EachValidator
|
3535
|
+
# def validate_each(record, attribute, value)
|
3536
|
+
# record.errors.add attribute, (options[:message] || "is not an email") unless
|
3537
|
+
# value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
|
3538
|
+
# end
|
3539
|
+
# end
|
3540
|
+
#
|
3541
|
+
# class Person
|
3542
|
+
# include ActiveModel::Validations
|
3543
|
+
# attr_accessor :name, :email
|
3544
|
+
#
|
3545
|
+
# validates :name, presence: true, length: { maximum: 100 }
|
3546
|
+
# validates :email, presence: true, email: true
|
3547
|
+
# end
|
3548
|
+
#
|
3549
|
+
# Validator classes may also exist within the class being validated
|
3550
|
+
# allowing custom modules of validators to be included as needed.
|
3551
|
+
#
|
3552
|
+
# class Film
|
3553
|
+
# include ActiveModel::Validations
|
3554
|
+
#
|
3555
|
+
# class TitleValidator < ActiveModel::EachValidator
|
3556
|
+
# def validate_each(record, attribute, value)
|
3557
|
+
# record.errors.add attribute, "must start with 'the'" unless value =~ /\Athe/i
|
3558
|
+
# end
|
3559
|
+
# end
|
3560
|
+
#
|
3561
|
+
# validates :name, title: true
|
3562
|
+
# end
|
3563
|
+
#
|
3564
|
+
# Additionally validator classes may be in another namespace and still
|
3565
|
+
# used within any class.
|
3566
|
+
#
|
3567
|
+
# validates :name, :'film/title' => true
|
3568
|
+
#
|
3569
|
+
# The validators hash can also handle regular expressions, ranges, arrays
|
3570
|
+
# and strings in shortcut form.
|
3571
|
+
#
|
3572
|
+
# validates :email, format: /@/
|
3573
|
+
# validates :role, inclusion: %(admin contributor)
|
3574
|
+
# validates :password, length: 6..20
|
3575
|
+
#
|
3576
|
+
# When using shortcut form, ranges and arrays are passed to your
|
3577
|
+
# validator's initializer as <tt>options[:in]</tt> while other types
|
3578
|
+
# including regular expressions and strings are passed as <tt>options[:with]</tt>.
|
3579
|
+
#
|
3580
|
+
# There is also a list of options that could be used along with validators:
|
3581
|
+
#
|
3582
|
+
# * <tt>:on</tt> - Specifies the contexts where this validation is active.
|
3583
|
+
# Runs in all validation contexts by default +nil+. You can pass a symbol
|
3584
|
+
# or an array of symbols. (e.g. <tt>on: :create</tt> or
|
3585
|
+
# <tt>on: :custom_validation_context</tt> or
|
3586
|
+
# <tt>on: [:create, :custom_validation_context]</tt>)
|
3587
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
3588
|
+
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
|
3589
|
+
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
|
3590
|
+
# proc or string should return or evaluate to a +true+ or +false+ value.
|
3591
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
|
3592
|
+
# if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
|
3593
|
+
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
3594
|
+
# method, proc or string should return or evaluate to a +true+ or
|
3595
|
+
# +false+ value.
|
3596
|
+
# * <tt>:allow_nil</tt> - Skip validation if the attribute is +nil+.
|
3597
|
+
# * <tt>:allow_blank</tt> - Skip validation if the attribute is blank.
|
3598
|
+
# * <tt>:strict</tt> - If the <tt>:strict</tt> option is set to true
|
3599
|
+
# will raise ActiveModel::StrictValidationFailed instead of adding the error.
|
3600
|
+
# <tt>:strict</tt> option can also be set to any other exception.
|
3601
|
+
#
|
3602
|
+
# Example:
|
3603
|
+
#
|
3604
|
+
# validates :password, presence: true, confirmation: true, if: :password_required?
|
3605
|
+
# validates :token, length: 24, strict: TokenLengthException
|
3606
|
+
#
|
3607
|
+
#
|
3608
|
+
# Finally, the options +:if+, +:unless+, +:on+, +:allow_blank+, +:allow_nil+, +:strict+
|
3609
|
+
# and +:message+ can be given to one specific validator, as a hash:
|
3610
|
+
#
|
3611
|
+
# validates :password, presence: { if: :password_required?, message: 'is forgotten.' }, confirmation: true
|
3612
|
+
def validates: (*untyped attributes) -> untyped
|
3613
|
+
|
3614
|
+
# This method is used to define validations that cannot be corrected by end
|
3615
|
+
# users and are considered exceptional. So each validator defined with bang
|
3616
|
+
# or <tt>:strict</tt> option set to <tt>true</tt> will always raise
|
3617
|
+
# <tt>ActiveModel::StrictValidationFailed</tt> instead of adding error
|
3618
|
+
# when validation fails. See <tt>validates</tt> for more information about
|
3619
|
+
# the validation itself.
|
3620
|
+
#
|
3621
|
+
# class Person
|
3622
|
+
# include ActiveModel::Validations
|
3623
|
+
#
|
3624
|
+
# attr_accessor :name
|
3625
|
+
# validates! :name, presence: true
|
3626
|
+
# end
|
3627
|
+
#
|
3628
|
+
# person = Person.new
|
3629
|
+
# person.name = ''
|
3630
|
+
# person.valid?
|
3631
|
+
# # => ActiveModel::StrictValidationFailed: Name can't be blank
|
3632
|
+
def validates!: (*untyped attributes) -> untyped
|
3633
|
+
|
3634
|
+
# When creating custom validators, it might be useful to be able to specify
|
3635
|
+
# additional default keys. This can be done by overwriting this method.
|
3636
|
+
def _validates_default_keys: () -> ::Array[:if | :unless | :on | :allow_blank | :allow_nil | :strict]
|
3637
|
+
|
3638
|
+
def _parse_validates_options: (untyped options) -> untyped
|
3639
|
+
|
3640
|
+
# Passes the record off to the class or classes specified and allows them
|
3641
|
+
# to add errors based on more complex conditions.
|
3642
|
+
#
|
3643
|
+
# class Person
|
3644
|
+
# include ActiveModel::Validations
|
3645
|
+
# validates_with MyValidator
|
3646
|
+
# end
|
3647
|
+
#
|
3648
|
+
# class MyValidator < ActiveModel::Validator
|
3649
|
+
# def validate(record)
|
3650
|
+
# if some_complex_logic
|
3651
|
+
# record.errors.add :base, 'This record is invalid'
|
3652
|
+
# end
|
3653
|
+
# end
|
3654
|
+
#
|
3655
|
+
# private
|
3656
|
+
# def some_complex_logic
|
3657
|
+
# # ...
|
3658
|
+
# end
|
3659
|
+
# end
|
3660
|
+
#
|
3661
|
+
# You may also pass it multiple classes, like so:
|
3662
|
+
#
|
3663
|
+
# class Person
|
3664
|
+
# include ActiveModel::Validations
|
3665
|
+
# validates_with MyValidator, MyOtherValidator, on: :create
|
3666
|
+
# end
|
3667
|
+
#
|
3668
|
+
# Configuration options:
|
3669
|
+
# * <tt>:on</tt> - Specifies the contexts where this validation is active.
|
3670
|
+
# Runs in all validation contexts by default +nil+. You can pass a symbol
|
3671
|
+
# or an array of symbols. (e.g. <tt>on: :create</tt> or
|
3672
|
+
# <tt>on: :custom_validation_context</tt> or
|
3673
|
+
# <tt>on: [:create, :custom_validation_context]</tt>)
|
3674
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
3675
|
+
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
|
3676
|
+
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>).
|
3677
|
+
# The method, proc or string should return or evaluate to a +true+ or
|
3678
|
+
# +false+ value.
|
3679
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
|
3680
|
+
# determine if the validation should not occur
|
3681
|
+
# (e.g. <tt>unless: :skip_validation</tt>, or
|
3682
|
+
# <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>).
|
3683
|
+
# The method, proc or string should return or evaluate to a +true+ or
|
3684
|
+
# +false+ value.
|
3685
|
+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
|
3686
|
+
# See <tt>ActiveModel::Validations#validates!</tt> for more information.
|
3687
|
+
#
|
3688
|
+
# If you pass any additional configuration options, they will be passed
|
3689
|
+
# to the class and available as +options+:
|
3690
|
+
#
|
3691
|
+
# class Person
|
3692
|
+
# include ActiveModel::Validations
|
3693
|
+
# validates_with MyValidator, my_custom_key: 'my custom value'
|
3694
|
+
# end
|
3695
|
+
#
|
3696
|
+
# class MyValidator < ActiveModel::Validator
|
3697
|
+
# def validate(record)
|
3698
|
+
# options[:my_custom_key] # => "my custom value"
|
3699
|
+
# end
|
3700
|
+
# end
|
3701
|
+
def validates_with: (*untyped args) { () -> untyped } -> untyped
|
3702
|
+
end
|
3703
|
+
|
3704
|
+
ActiveModel::Validations::ClassMethods::VALID_OPTIONS_FOR_VALIDATE: untyped
|
3705
|
+
|
3706
|
+
# = Active Model ValidationError
|
3707
|
+
#
|
3708
|
+
# Raised by <tt>validate!</tt> when the model is invalid. Use the
|
3709
|
+
# +model+ method to retrieve the record which did not validate.
|
3710
|
+
#
|
3711
|
+
# begin
|
3712
|
+
# complex_operation_that_internally_calls_validate!
|
3713
|
+
# rescue ActiveModel::ValidationError => invalid
|
3714
|
+
# puts invalid.model.errors
|
3715
|
+
# end
|
3716
|
+
class ActiveModel::ValidationError < StandardError
|
3717
|
+
attr_reader model: untyped
|
3718
|
+
|
3719
|
+
def initialize: (untyped model) -> untyped
|
3720
|
+
end
|
3721
|
+
|
3722
|
+
class ActiveModel::Validations::WithValidator < EachValidator
|
3723
|
+
# :nodoc:
|
3724
|
+
def validate_each: (untyped record, untyped attr, untyped val) -> untyped
|
3725
|
+
end
|
3726
|
+
|
3727
|
+
# == Active \Model \Validator
|
3728
|
+
#
|
3729
|
+
# A simple base class that can be used along with
|
3730
|
+
# ActiveModel::Validations::ClassMethods.validates_with
|
3731
|
+
#
|
3732
|
+
# class Person
|
3733
|
+
# include ActiveModel::Validations
|
3734
|
+
# validates_with MyValidator
|
3735
|
+
# end
|
3736
|
+
#
|
3737
|
+
# class MyValidator < ActiveModel::Validator
|
3738
|
+
# def validate(record)
|
3739
|
+
# if some_complex_logic
|
3740
|
+
# record.errors.add(:base, "This record is invalid")
|
3741
|
+
# end
|
3742
|
+
# end
|
3743
|
+
#
|
3744
|
+
# private
|
3745
|
+
# def some_complex_logic
|
3746
|
+
# # ...
|
3747
|
+
# end
|
3748
|
+
# end
|
3749
|
+
#
|
3750
|
+
# Any class that inherits from ActiveModel::Validator must implement a method
|
3751
|
+
# called +validate+ which accepts a +record+.
|
3752
|
+
#
|
3753
|
+
# class Person
|
3754
|
+
# include ActiveModel::Validations
|
3755
|
+
# validates_with MyValidator
|
3756
|
+
# end
|
3757
|
+
#
|
3758
|
+
# class MyValidator < ActiveModel::Validator
|
3759
|
+
# def validate(record)
|
3760
|
+
# record # => The person instance being validated
|
3761
|
+
# options # => Any non-standard options passed to validates_with
|
3762
|
+
# end
|
3763
|
+
# end
|
3764
|
+
#
|
3765
|
+
# To cause a validation error, you must add to the +record+'s errors directly
|
3766
|
+
# from within the validators message.
|
3767
|
+
#
|
3768
|
+
# class MyValidator < ActiveModel::Validator
|
3769
|
+
# def validate(record)
|
3770
|
+
# record.errors.add :base, "This is some custom error message"
|
3771
|
+
# record.errors.add :first_name, "This is some complex validation"
|
3772
|
+
# # etc...
|
3773
|
+
# end
|
3774
|
+
# end
|
3775
|
+
#
|
3776
|
+
# To add behavior to the initialize method, use the following signature:
|
3777
|
+
#
|
3778
|
+
# class MyValidator < ActiveModel::Validator
|
3779
|
+
# def initialize(options)
|
3780
|
+
# super
|
3781
|
+
# @my_custom_field = options[:field_name] || :first_name
|
3782
|
+
# end
|
3783
|
+
# end
|
3784
|
+
#
|
3785
|
+
# Note that the validator is initialized only once for the whole application
|
3786
|
+
# life cycle, and not on each validation run.
|
3787
|
+
#
|
3788
|
+
# The easiest way to add custom validators for validating individual attributes
|
3789
|
+
# is with the convenient <tt>ActiveModel::EachValidator</tt>.
|
3790
|
+
#
|
3791
|
+
# class TitleValidator < ActiveModel::EachValidator
|
3792
|
+
# def validate_each(record, attribute, value)
|
3793
|
+
# record.errors.add attribute, 'must be Mr., Mrs., or Dr.' unless %w(Mr. Mrs. Dr.).include?(value)
|
3794
|
+
# end
|
3795
|
+
# end
|
3796
|
+
#
|
3797
|
+
# This can now be used in combination with the +validates+ method
|
3798
|
+
# (see <tt>ActiveModel::Validations::ClassMethods.validates</tt> for more on this).
|
3799
|
+
#
|
3800
|
+
# class Person
|
3801
|
+
# include ActiveModel::Validations
|
3802
|
+
# attr_accessor :title
|
3803
|
+
#
|
3804
|
+
# validates :title, presence: true, title: true
|
3805
|
+
# end
|
3806
|
+
#
|
3807
|
+
# It can be useful to access the class that is using that validator when there are prerequisites such
|
3808
|
+
# as an +attr_accessor+ being present. This class is accessible via <tt>options[:class]</tt> in the constructor.
|
3809
|
+
# To setup your validator override the constructor.
|
3810
|
+
#
|
3811
|
+
# class MyValidator < ActiveModel::Validator
|
3812
|
+
# def initialize(options={})
|
3813
|
+
# super
|
3814
|
+
# options[:class].attr_accessor :custom_attribute
|
3815
|
+
# end
|
3816
|
+
# end
|
3817
|
+
class ActiveModel::Validator
|
3818
|
+
attr_reader options: untyped
|
3819
|
+
|
3820
|
+
# Returns the kind of the validator.
|
3821
|
+
#
|
3822
|
+
# PresenceValidator.kind # => :presence
|
3823
|
+
# AcceptanceValidator.kind # => :acceptance
|
3824
|
+
def self.kind: () -> untyped
|
3825
|
+
|
3826
|
+
# Accepts options that will be made available through the +options+ reader.
|
3827
|
+
def initialize: (?::Hash[untyped, untyped] options) -> untyped
|
3828
|
+
|
3829
|
+
# Returns the kind for this validator.
|
3830
|
+
#
|
3831
|
+
# PresenceValidator.new(attributes: [:username]).kind # => :presence
|
3832
|
+
# AcceptanceValidator.new(attributes: [:terms]).kind # => :acceptance
|
3833
|
+
def kind: () -> untyped
|
3834
|
+
|
3835
|
+
# Override this method in subclasses with validation logic, adding errors
|
3836
|
+
# to the records +errors+ array where necessary.
|
3837
|
+
def validate: (untyped record) -> untyped
|
3838
|
+
end
|
3839
|
+
|
3840
|
+
class ActiveModel::EachValidator < Validator
|
3841
|
+
# +EachValidator+ is a validator which iterates through the attributes given
|
3842
|
+
# in the options hash invoking the <tt>validate_each</tt> method passing in the
|
3843
|
+
# record, attribute and value.
|
3844
|
+
#
|
3845
|
+
# All \Active \Model validations are built on top of this validator.
|
3846
|
+
# nodoc:
|
3847
|
+
attr_reader attributes: untyped
|
3848
|
+
|
3849
|
+
# Returns a new validator instance. All options will be available via the
|
3850
|
+
# +options+ reader, however the <tt>:attributes</tt> option will be removed
|
3851
|
+
# and instead be made available through the +attributes+ reader.
|
3852
|
+
def initialize: (untyped options) -> untyped
|
3853
|
+
|
3854
|
+
# Performs validation on the supplied record. By default this will call
|
3855
|
+
# +validate_each+ to determine validity therefore subclasses should
|
3856
|
+
# override +validate_each+ with validation logic.
|
3857
|
+
def validate: (untyped record) -> untyped
|
3858
|
+
|
3859
|
+
# Override this method in subclasses with the validation logic, adding
|
3860
|
+
# errors to the records +errors+ array where necessary.
|
3861
|
+
def validate_each: (untyped record, untyped attribute, untyped value) -> untyped
|
3862
|
+
|
3863
|
+
# Hook method that gets called by the initializer allowing verification
|
3864
|
+
# that the arguments supplied are valid. You could for example raise an
|
3865
|
+
# +ArgumentError+ when invalid options are supplied.
|
3866
|
+
def check_validity!: () -> nil
|
3867
|
+
end
|
3868
|
+
|
3869
|
+
class ActiveModel::BlockValidator < EachValidator
|
3870
|
+
# +BlockValidator+ is a special +EachValidator+ which receives a block on initialization
|
3871
|
+
# and call this block for each attribute being validated. +validates_each+ uses this validator.
|
3872
|
+
# nodoc:
|
3873
|
+
def initialize: (untyped options) { () -> untyped } -> untyped
|
3874
|
+
|
3875
|
+
def validate_each: (untyped record, untyped attribute, untyped value) -> untyped
|
3876
|
+
end
|
3877
|
+
|