activerecord 7.0.3.1 → 7.0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +128 -0
- data/lib/active_record/associations/collection_association.rb +0 -1
- data/lib/active_record/associations/collection_proxy.rb +1 -1
- data/lib/active_record/associations/has_many_association.rb +7 -4
- data/lib/active_record/associations/join_dependency.rb +17 -13
- data/lib/active_record/associations.rb +6 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
- data/lib/active_record/coders/yaml_column.rb +11 -5
- data/lib/active_record/connection_adapters/abstract/quoting.rb +10 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +5 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +7 -2
- data/lib/active_record/delegated_type.rb +1 -1
- data/lib/active_record/encryption/message.rb +1 -1
- data/lib/active_record/encryption/properties.rb +1 -1
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/middleware/database_selector.rb +1 -1
- data/lib/active_record/model_schema.rb +21 -9
- data/lib/active_record/query_logs.rb +12 -1
- data/lib/active_record/railtie.rb +6 -34
- data/lib/active_record/railties/databases.rake +15 -10
- data/lib/active_record/relation/query_methods.rb +21 -5
- data/lib/active_record/relation.rb +1 -0
- data/lib/active_record/scoping/default.rb +4 -2
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/store.rb +7 -2
- data/lib/active_record/test_fixtures.rb +9 -5
- data/lib/active_record.rb +9 -1
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a5c0c6f9ce9d898d0ec937ec3d4c6ea37ae02637d8aee9cf219ac5acdec5236
|
4
|
+
data.tar.gz: 2d19932b94835dcbd398676c2528177c11f9437edc7068f44f314449ccb5abe0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3746715cb1a4b90ed3ce96f4826006657d450215af9f96179e53ad32b967dbad06d0328e6c18e0eedf3a576fe5efedc9c546c07149801b90c4e5eb537a3962c
|
7
|
+
data.tar.gz: a5cf64d8fbaf1023b35d22865468a824ae13a3c243b3c1084bbfafcad432a84df322346b9143a6e98273202da674bf0d3e521d903ad450209fc014998127e223
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,131 @@
|
|
1
|
+
## Rails 7.0.4.1 (January 17, 2023) ##
|
2
|
+
|
3
|
+
* Make sanitize_as_sql_comment more strict
|
4
|
+
|
5
|
+
Though this method was likely never meant to take user input, it was
|
6
|
+
attempting sanitization. That sanitization could be bypassed with
|
7
|
+
carefully crafted input.
|
8
|
+
|
9
|
+
This commit makes the sanitization more robust by replacing any
|
10
|
+
occurrances of "/*" or "*/" with "/ *" or "* /". It also performs a
|
11
|
+
first pass to remove one surrounding comment to avoid compatibility
|
12
|
+
issues for users relying on the existing removal.
|
13
|
+
|
14
|
+
This also clarifies in the documentation of annotate that it should not
|
15
|
+
be provided user input.
|
16
|
+
|
17
|
+
[CVE-2023-22794]
|
18
|
+
|
19
|
+
* Added integer width check to PostgreSQL::Quoting
|
20
|
+
|
21
|
+
Given a value outside the range for a 64bit signed integer type
|
22
|
+
PostgreSQL will treat the column type as numeric. Comparing
|
23
|
+
integer values against numeric values can result in a slow
|
24
|
+
sequential scan.
|
25
|
+
|
26
|
+
This behavior is configurable via
|
27
|
+
ActiveRecord::Base.raise_int_wider_than_64bit which defaults to true.
|
28
|
+
|
29
|
+
[CVE-2022-44566]
|
30
|
+
|
31
|
+
|
32
|
+
## Rails 7.0.4 (September 09, 2022) ##
|
33
|
+
|
34
|
+
* Symbol is allowed by default for YAML columns
|
35
|
+
|
36
|
+
*Étienne Barrié*
|
37
|
+
|
38
|
+
* Fix `ActiveRecord::Store` to serialize as a regular Hash
|
39
|
+
|
40
|
+
Previously it would serialize as an `ActiveSupport::HashWithIndifferentAccess`
|
41
|
+
which is wasteful and cause problem with YAML safe_load.
|
42
|
+
|
43
|
+
*Jean Boussier*
|
44
|
+
|
45
|
+
* Add `timestamptz` as a time zone aware type for PostgreSQL
|
46
|
+
|
47
|
+
This is required for correctly parsing `timestamp with time zone` values in your database.
|
48
|
+
|
49
|
+
If you don't want this, you can opt out by adding this initializer:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
ActiveRecord::Base.time_zone_aware_types -= [:timestamptz]
|
53
|
+
```
|
54
|
+
|
55
|
+
*Alex Ghiculescu*
|
56
|
+
|
57
|
+
* Fix supporting timezone awareness for `tsrange` and `tstzrange` array columns.
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
# In database migrations
|
61
|
+
add_column :shops, :open_hours, :tsrange, array: true
|
62
|
+
# In app config
|
63
|
+
ActiveRecord::Base.time_zone_aware_types += [:tsrange]
|
64
|
+
# In the code times are properly converted to app time zone
|
65
|
+
Shop.create!(open_hours: [Time.current..8.hour.from_now])
|
66
|
+
```
|
67
|
+
|
68
|
+
*Wojciech Wnętrzak*
|
69
|
+
|
70
|
+
* Resolve issue where a relation cache_version could be left stale.
|
71
|
+
|
72
|
+
Previously, when `reset` was called on a relation object it did not reset the cache_versions
|
73
|
+
ivar. This led to a confusing situation where despite having the correct data the relation
|
74
|
+
still reported a stale cache_version.
|
75
|
+
|
76
|
+
Usage:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
developers = Developer.all
|
80
|
+
developers.cache_version
|
81
|
+
|
82
|
+
Developer.update_all(updated_at: Time.now.utc + 1.second)
|
83
|
+
|
84
|
+
developers.cache_version # Stale cache_version
|
85
|
+
developers.reset
|
86
|
+
developers.cache_version # Returns the current correct cache_version
|
87
|
+
```
|
88
|
+
|
89
|
+
Fixes #45341.
|
90
|
+
|
91
|
+
*Austen Madden*
|
92
|
+
|
93
|
+
* Fix `load_async` when called on an association proxy.
|
94
|
+
|
95
|
+
Calling `load_async` directly an association would schedule
|
96
|
+
a query but never use it.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
comments = post.comments.load_async # schedule a query
|
100
|
+
comments.to_a # perform an entirely new sync query
|
101
|
+
```
|
102
|
+
|
103
|
+
Now it does use the async query, however note that it doesn't
|
104
|
+
cause the association to be loaded.
|
105
|
+
|
106
|
+
*Jean Boussier*
|
107
|
+
|
108
|
+
* Fix eager loading for models without primary keys.
|
109
|
+
|
110
|
+
*Anmol Chopra*, *Matt Lawrence*, and *Jonathan Hefner*
|
111
|
+
|
112
|
+
* `rails db:schema:{dump,load}` now checks `ENV["SCHEMA_FORMAT"]` before config
|
113
|
+
|
114
|
+
Since `rails db:structure:{dump,load}` was deprecated there wasn't a simple
|
115
|
+
way to dump a schema to both SQL and Ruby formats. You can now do this with
|
116
|
+
an environment variable. For example:
|
117
|
+
|
118
|
+
```
|
119
|
+
SCHEMA_FORMAT=sql rake db:schema:dump
|
120
|
+
```
|
121
|
+
|
122
|
+
*Alex Ghiculescu*
|
123
|
+
|
124
|
+
* Fix Hstore deserialize regression.
|
125
|
+
|
126
|
+
*edsharp*
|
127
|
+
|
128
|
+
|
1
129
|
## Rails 7.0.3.1 (July 12, 2022) ##
|
2
130
|
|
3
131
|
* Change ActiveRecord::Coders::YAMLColumn default to safe_load
|
@@ -320,7 +320,6 @@ module ActiveRecord
|
|
320
320
|
# * Otherwise, attributes should have the value found in the database
|
321
321
|
def merge_target_lists(persisted, memory)
|
322
322
|
return persisted if memory.empty?
|
323
|
-
return memory if persisted.empty?
|
324
323
|
|
325
324
|
persisted.map! do |record|
|
326
325
|
if mem_record = memory.delete(record)
|
@@ -1108,7 +1108,7 @@ module ActiveRecord
|
|
1108
1108
|
].flat_map { |klass|
|
1109
1109
|
klass.public_instance_methods(false)
|
1110
1110
|
} - self.public_instance_methods(false) - [:select] + [
|
1111
|
-
:scoping, :values, :insert, :insert_all, :insert!, :insert_all!, :upsert, :upsert_all
|
1111
|
+
:scoping, :values, :insert, :insert_all, :insert!, :insert_all!, :upsert, :upsert_all, :load_async
|
1112
1112
|
]
|
1113
1113
|
|
1114
1114
|
delegate(*delegate_methods, to: :scope)
|
@@ -79,10 +79,13 @@ module ActiveRecord
|
|
79
79
|
scope.count(:all)
|
80
80
|
end
|
81
81
|
|
82
|
-
# If there's nothing in the database
|
83
|
-
#
|
84
|
-
#
|
85
|
-
|
82
|
+
# If there's nothing in the database, @target should only contain new
|
83
|
+
# records or be an empty array. This is a documented side-effect of
|
84
|
+
# the method that may avoid an extra SELECT.
|
85
|
+
if count == 0
|
86
|
+
target.select!(&:new_record?)
|
87
|
+
loaded!
|
88
|
+
end
|
86
89
|
|
87
90
|
[association_scope.limit_value, count].compact.min
|
88
91
|
end
|
@@ -252,35 +252,39 @@ module ActiveRecord
|
|
252
252
|
next
|
253
253
|
end
|
254
254
|
|
255
|
-
|
256
|
-
|
257
|
-
|
255
|
+
if node.primary_key
|
256
|
+
key = aliases.column_alias(node, node.primary_key)
|
257
|
+
id = row[key]
|
258
|
+
else
|
259
|
+
key = aliases.column_alias(node, node.reflection.join_primary_key.to_s)
|
260
|
+
id = nil # Avoid id-based model caching.
|
261
|
+
end
|
262
|
+
|
263
|
+
if row[key].nil?
|
258
264
|
nil_association = ar_parent.association(node.reflection.name)
|
259
265
|
nil_association.loaded!
|
260
266
|
next
|
261
267
|
end
|
262
268
|
|
263
|
-
model = seen[ar_parent][node][id]
|
264
|
-
|
265
|
-
if model
|
266
|
-
construct(model, node, row, seen, model_cache, strict_loading_value)
|
267
|
-
else
|
269
|
+
unless model = seen[ar_parent][node][id]
|
268
270
|
model = construct_model(ar_parent, node, row, model_cache, id, strict_loading_value)
|
269
|
-
|
270
|
-
seen[ar_parent][node][id] = model
|
271
|
-
construct(model, node, row, seen, model_cache, strict_loading_value)
|
271
|
+
seen[ar_parent][node][id] = model if id
|
272
272
|
end
|
273
|
+
|
274
|
+
construct(model, node, row, seen, model_cache, strict_loading_value)
|
273
275
|
end
|
274
276
|
end
|
275
277
|
|
276
278
|
def construct_model(record, node, row, model_cache, id, strict_loading_value)
|
277
279
|
other = record.association(node.reflection.name)
|
278
280
|
|
279
|
-
model = model_cache[node][id]
|
280
|
-
node.instantiate(row, aliases.column_aliases(node)) do |m|
|
281
|
+
unless model = model_cache[node][id]
|
282
|
+
model = node.instantiate(row, aliases.column_aliases(node)) do |m|
|
281
283
|
m.strict_loading! if strict_loading_value
|
282
284
|
other.set_inverse_instance(m)
|
283
285
|
end
|
286
|
+
model_cache[node][id] = model if id
|
287
|
+
end
|
284
288
|
|
285
289
|
if node.reflection.collection?
|
286
290
|
other.target.push(model)
|
@@ -628,15 +628,15 @@ module ActiveRecord
|
|
628
628
|
#
|
629
629
|
# Note: To trigger remove callbacks, you must use +destroy+ / +destroy_all+ methods. For example:
|
630
630
|
#
|
631
|
-
#
|
632
|
-
#
|
633
|
-
#
|
631
|
+
# * <tt>firm.clients.destroy(client)</tt>
|
632
|
+
# * <tt>firm.clients.destroy(*clients)</tt>
|
633
|
+
# * <tt>firm.clients.destroy_all</tt>
|
634
634
|
#
|
635
635
|
# +delete+ / +delete_all+ methods like the following do *not* trigger remove callbacks:
|
636
636
|
#
|
637
|
-
#
|
638
|
-
#
|
639
|
-
#
|
637
|
+
# * <tt>firm.clients.delete(client)</tt>
|
638
|
+
# * <tt>firm.clients.delete(*clients)</tt>
|
639
|
+
# * <tt>firm.clients.delete_all</tt>
|
640
640
|
#
|
641
641
|
# == Association extensions
|
642
642
|
#
|
@@ -19,6 +19,8 @@ module ActiveRecord
|
|
19
19
|
|
20
20
|
if value.is_a?(Hash)
|
21
21
|
set_time_zone_without_conversion(super)
|
22
|
+
elsif value.is_a?(Range)
|
23
|
+
Range.new(user_input_in_time_zone(value.begin), user_input_in_time_zone(value.end), value.exclude_end?)
|
22
24
|
elsif value.respond_to?(:in_time_zone)
|
23
25
|
begin
|
24
26
|
super(user_input_in_time_zone(value)) || super
|
@@ -40,6 +42,8 @@ module ActiveRecord
|
|
40
42
|
value.in_time_zone
|
41
43
|
elsif value.respond_to?(:infinite?) && value.infinite?
|
42
44
|
value
|
45
|
+
elsif value.is_a?(Range)
|
46
|
+
Range.new(convert_time_to_time_zone(value.begin), convert_time_to_time_zone(value.end), value.exclude_end?)
|
43
47
|
else
|
44
48
|
map_avoiding_infinite_recursion(value) { |v| convert_time_to_time_zone(v) }
|
45
49
|
end
|
@@ -45,14 +45,20 @@ module ActiveRecord
|
|
45
45
|
raise ArgumentError, "Cannot serialize #{object_class}. Classes passed to `serialize` must have a 0 argument constructor."
|
46
46
|
end
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
else
|
52
|
-
if YAML.respond_to?(:unsafe_load)
|
48
|
+
if YAML.respond_to?(:unsafe_load)
|
49
|
+
def yaml_load(payload)
|
50
|
+
if ActiveRecord.use_yaml_unsafe_load
|
53
51
|
YAML.unsafe_load(payload)
|
54
52
|
else
|
53
|
+
YAML.safe_load(payload, permitted_classes: ActiveRecord.yaml_column_permitted_classes, aliases: true)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
else
|
57
|
+
def yaml_load(payload)
|
58
|
+
if ActiveRecord.use_yaml_unsafe_load
|
55
59
|
YAML.load(payload)
|
60
|
+
else
|
61
|
+
YAML.safe_load(payload, permitted_classes: ActiveRecord.yaml_column_permitted_classes, aliases: true)
|
56
62
|
end
|
57
63
|
end
|
58
64
|
end
|
@@ -146,7 +146,16 @@ module ActiveRecord
|
|
146
146
|
end
|
147
147
|
|
148
148
|
def sanitize_as_sql_comment(value) # :nodoc:
|
149
|
-
|
149
|
+
# Sanitize a string to appear within a SQL comment
|
150
|
+
# For compatibility, this also surrounding "/*+", "/*", and "*/"
|
151
|
+
# charcacters, possibly with single surrounding space.
|
152
|
+
# Then follows that by replacing any internal "*/" or "/ *" with
|
153
|
+
# "* /" or "/ *"
|
154
|
+
comment = value.to_s.dup
|
155
|
+
comment.gsub!(%r{\A\s*/\*\+?\s?|\s?\*/\s*\Z}, "")
|
156
|
+
comment.gsub!("*/", "* /")
|
157
|
+
comment.gsub!("/*", "/ *")
|
158
|
+
comment
|
150
159
|
end
|
151
160
|
|
152
161
|
def column_name_matcher # :nodoc:
|
@@ -139,7 +139,7 @@ module ActiveRecord
|
|
139
139
|
end
|
140
140
|
|
141
141
|
def field_ordered_value(column, values) # :nodoc:
|
142
|
-
field = Arel::Nodes::NamedFunction.new("FIELD", [column, values.reverse])
|
142
|
+
field = Arel::Nodes::NamedFunction.new("FIELD", [column, values.reverse.map { |value| Arel::Nodes.build_quoted(value) }])
|
143
143
|
Arel::Nodes::Descending.new(field)
|
144
144
|
end
|
145
145
|
|
@@ -711,6 +711,10 @@ module ActiveRecord
|
|
711
711
|
options[:comment] = column.comment
|
712
712
|
end
|
713
713
|
|
714
|
+
unless options.key?(:collation)
|
715
|
+
options[:collation] = column.collation
|
716
|
+
end
|
717
|
+
|
714
718
|
unless options.key?(:auto_increment)
|
715
719
|
options[:auto_increment] = column.auto_increment?
|
716
720
|
end
|
@@ -159,7 +159,7 @@ module ActiveRecord
|
|
159
159
|
end
|
160
160
|
|
161
161
|
def default_type(table_name, field_name)
|
162
|
-
match = create_table_info(table_name)
|
162
|
+
match = create_table_info(table_name)&.match(/`#{field_name}` (.+) DEFAULT ('|\d+|[A-z]+)/)
|
163
163
|
default_pre = match[2] if match
|
164
164
|
|
165
165
|
if default_pre == "'"
|
@@ -26,7 +26,7 @@ module ActiveRecord
|
|
26
26
|
raise(ArgumentError, ERROR % scanner.string.inspect)
|
27
27
|
end
|
28
28
|
|
29
|
-
unless key = scanner.
|
29
|
+
unless key = scanner.scan(/^(\\[\\"]|[^\\"])*?(?=")/)
|
30
30
|
raise(ArgumentError, ERROR % scanner.string.inspect)
|
31
31
|
end
|
32
32
|
|
@@ -41,7 +41,7 @@ module ActiveRecord
|
|
41
41
|
raise(ArgumentError, ERROR % scanner.string.inspect)
|
42
42
|
end
|
43
43
|
|
44
|
-
unless value = scanner.
|
44
|
+
unless value = scanner.scan(/^(\\[\\"]|[^\\"])*?(?=")/)
|
45
45
|
raise(ArgumentError, ERROR % scanner.string.inspect)
|
46
46
|
end
|
47
47
|
|
@@ -4,6 +4,12 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module PostgreSQL
|
6
6
|
module Quoting
|
7
|
+
class IntegerOutOf64BitRange < StandardError
|
8
|
+
def initialize(msg)
|
9
|
+
super(msg)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
7
13
|
# Escapes binary strings for bytea input to the database.
|
8
14
|
def escape_bytea(value)
|
9
15
|
@connection.escape_bytea(value) if value
|
@@ -16,7 +22,27 @@ module ActiveRecord
|
|
16
22
|
@connection.unescape_bytea(value) if value
|
17
23
|
end
|
18
24
|
|
25
|
+
def check_int_in_range(value)
|
26
|
+
if value.to_int > 9223372036854775807 || value.to_int < -9223372036854775808
|
27
|
+
exception = <<~ERROR
|
28
|
+
Provided value outside of the range of a signed 64bit integer.
|
29
|
+
|
30
|
+
PostgreSQL will treat the column type in question as a numeric.
|
31
|
+
This may result in a slow sequential scan due to a comparison
|
32
|
+
being performed between an integer or bigint value and a numeric value.
|
33
|
+
|
34
|
+
To allow for this potentially unwanted behavior, set
|
35
|
+
ActiveRecord.raise_int_wider_than_64bit to false.
|
36
|
+
ERROR
|
37
|
+
raise IntegerOutOf64BitRange.new exception
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
19
41
|
def quote(value) # :nodoc:
|
42
|
+
if ActiveRecord.raise_int_wider_than_64bit && value.is_a?(Integer)
|
43
|
+
check_int_in_range(value)
|
44
|
+
end
|
45
|
+
|
20
46
|
case value
|
21
47
|
when OID::Xml::Data
|
22
48
|
"xml '#{quote_string(value.to_s)}'"
|
@@ -45,8 +45,10 @@ Rails needs superuser privileges to disable referential integrity.
|
|
45
45
|
BEGIN
|
46
46
|
FOR r IN (
|
47
47
|
SELECT FORMAT(
|
48
|
-
'UPDATE pg_constraint SET convalidated=false WHERE conname = ''%I''; ALTER TABLE %I VALIDATE CONSTRAINT %I;',
|
48
|
+
'UPDATE pg_constraint SET convalidated=false WHERE conname = ''%I'' AND connamespace::regnamespace = ''%I''::regnamespace; ALTER TABLE %I.%I VALIDATE CONSTRAINT %I;',
|
49
49
|
constraint_name,
|
50
|
+
table_schema,
|
51
|
+
table_schema,
|
50
52
|
table_name,
|
51
53
|
constraint_name
|
52
54
|
) AS constraint_check
|
@@ -1063,5 +1063,6 @@ module ActiveRecord
|
|
1063
1063
|
ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
|
1064
1064
|
ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
|
1065
1065
|
end
|
1066
|
+
ActiveSupport.run_load_hooks(:active_record_postgresqladapter, PostgreSQLAdapter)
|
1066
1067
|
end
|
1067
1068
|
end
|
@@ -21,7 +21,7 @@ module ActiveRecord
|
|
21
21
|
WHERE name = #{quote(row['name'])} AND type = 'index'
|
22
22
|
SQL
|
23
23
|
|
24
|
-
/\bON\b\s*"?(\w+?)"?\s*\((?<expressions>.+?)\)(?:\s*WHERE\b\s*(?<where>.+))?\z/i =~ index_sql
|
24
|
+
/\bON\b\s*"?(\w+?)"?\s*\((?<expressions>.+?)\)(?:\s*WHERE\b\s*(?<where>.+))?(?:\s*\/\*.*\*\/)?\z/i =~ index_sql
|
25
25
|
|
26
26
|
columns = exec_query("PRAGMA index_info(#{quote(row['name'])})", "SCHEMA").map do |col|
|
27
27
|
col["name"]
|
@@ -341,7 +341,7 @@ module ActiveRecord
|
|
341
341
|
end
|
342
342
|
|
343
343
|
def get_database_version # :nodoc:
|
344
|
-
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
|
344
|
+
SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)", "SCHEMA"))
|
345
345
|
end
|
346
346
|
|
347
347
|
def check_version # :nodoc:
|
@@ -477,8 +477,13 @@ module ActiveRecord
|
|
477
477
|
options[:rename][column.name.to_sym] ||
|
478
478
|
column.name) : column.name
|
479
479
|
|
480
|
+
if column.has_default?
|
481
|
+
type = lookup_cast_type_from_column(column)
|
482
|
+
default = type.deserialize(column.default)
|
483
|
+
end
|
484
|
+
|
480
485
|
@definition.column(column_name, column.type,
|
481
|
-
limit: column.limit, default:
|
486
|
+
limit: column.limit, default: default,
|
482
487
|
precision: column.precision, scale: column.scale,
|
483
488
|
null: column.null, collation: column.collation,
|
484
489
|
primary_key: column_name == from_primary_key
|
@@ -136,7 +136,7 @@ module ActiveRecord
|
|
136
136
|
# end
|
137
137
|
# end
|
138
138
|
#
|
139
|
-
# Now you can list a bunch of entries, call
|
139
|
+
# Now you can list a bunch of entries, call <tt>Entry#title</tt>, and polymorphism will provide you with the answer.
|
140
140
|
#
|
141
141
|
# == Nested Attributes
|
142
142
|
#
|
@@ -12,7 +12,7 @@ module ActiveRecord
|
|
12
12
|
#
|
13
13
|
# message.headers.encrypted_data_key # instead of message.headers[:k]
|
14
14
|
#
|
15
|
-
# See +Properties
|
15
|
+
# See +Properties::DEFAULT_PROPERTIES+, Key, Message
|
16
16
|
class Properties
|
17
17
|
ALLOWED_VALUE_CLASSES = [String, ActiveRecord::Encryption::Message, Numeric, TrueClass, FalseClass, Symbol, NilClass]
|
18
18
|
|
@@ -44,7 +44,7 @@ module ActiveRecord
|
|
44
44
|
# config.active_record.database_resolver_context = MyResolver::MySession
|
45
45
|
#
|
46
46
|
# Note: If you are using `rails new my_app --minimal` you will need to call
|
47
|
-
# `require "active_support/core_ext/integer/time"` to load the
|
47
|
+
# `require "active_support/core_ext/integer/time"` to load the libraries
|
48
48
|
# for +Time+.
|
49
49
|
class DatabaseSelector
|
50
50
|
def initialize(app, resolver_klass = nil, context_klass = nil, options = {})
|
@@ -126,6 +126,27 @@ module ActiveRecord
|
|
126
126
|
# +:immutable_string+. This setting does not affect the behavior of
|
127
127
|
# <tt>attribute :foo, :string</tt>. Defaults to false.
|
128
128
|
|
129
|
+
##
|
130
|
+
# :singleton-method: inheritance_column
|
131
|
+
# :call-seq: inheritance_column
|
132
|
+
#
|
133
|
+
# The name of the table column which stores the class name on single-table
|
134
|
+
# inheritance situations.
|
135
|
+
#
|
136
|
+
# The default inheritance column name is +type+, which means it's a
|
137
|
+
# reserved word inside Active Record. To be able to use single-table
|
138
|
+
# inheritance with another column name, or to use the column +type+ in
|
139
|
+
# your own model for something else, you can set +inheritance_column+:
|
140
|
+
#
|
141
|
+
# self.inheritance_column = 'zoink'
|
142
|
+
|
143
|
+
##
|
144
|
+
# :singleton-method: inheritance_column=
|
145
|
+
# :call-seq: inheritance_column=(column)
|
146
|
+
#
|
147
|
+
# Defines the name of the table column which will store the class name on single-table
|
148
|
+
# inheritance situations.
|
149
|
+
|
129
150
|
included do
|
130
151
|
class_attribute :primary_key_prefix_type, instance_writer: false
|
131
152
|
class_attribute :table_name_prefix, instance_writer: false, default: ""
|
@@ -136,15 +157,6 @@ module ActiveRecord
|
|
136
157
|
class_attribute :implicit_order_column, instance_accessor: false
|
137
158
|
class_attribute :immutable_strings_by_default, instance_accessor: false
|
138
159
|
|
139
|
-
# Defines the name of the table column which will store the class name on single-table
|
140
|
-
# inheritance situations.
|
141
|
-
#
|
142
|
-
# The default inheritance column name is +type+, which means it's a
|
143
|
-
# reserved word inside Active Record. To be able to use single-table
|
144
|
-
# inheritance with another column name, or to use the column +type+ in
|
145
|
-
# your own model for something else, you can set +inheritance_column+:
|
146
|
-
#
|
147
|
-
# self.inheritance_column = 'zoink'
|
148
160
|
class_attribute :inheritance_column, instance_accessor: false, default: "type"
|
149
161
|
singleton_class.class_eval do
|
150
162
|
alias_method :_inheritance_column=, :inheritance_column=
|
@@ -33,6 +33,8 @@ module ActiveRecord
|
|
33
33
|
# want to add to the comment. Dynamic content can be created by setting a proc or lambda value in a hash,
|
34
34
|
# and can reference any value stored in the +context+ object.
|
35
35
|
#
|
36
|
+
# Escaping is performed on the string returned, however untrusted user input should not be used.
|
37
|
+
#
|
36
38
|
# Example:
|
37
39
|
#
|
38
40
|
# tags = [
|
@@ -109,7 +111,16 @@ module ActiveRecord
|
|
109
111
|
end
|
110
112
|
|
111
113
|
def escape_sql_comment(content)
|
112
|
-
|
114
|
+
# Sanitize a string to appear within a SQL comment
|
115
|
+
# For compatibility, this also surrounding "/*+", "/*", and "*/"
|
116
|
+
# charcacters, possibly with single surrounding space.
|
117
|
+
# Then follows that by replacing any internal "*/" or "/ *" with
|
118
|
+
# "* /" or "/ *"
|
119
|
+
comment = content.to_s.dup
|
120
|
+
comment.gsub!(%r{\A\s*/\*\+?\s?|\s?\*/\s*\Z}, "")
|
121
|
+
comment.gsub!("*/", "* /")
|
122
|
+
comment.gsub!("/*", "/ *")
|
123
|
+
comment
|
113
124
|
end
|
114
125
|
|
115
126
|
def tag_content
|
@@ -78,6 +78,12 @@ module ActiveRecord
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
+
initializer "active_record.postgresql_time_zone_aware_types" do
|
82
|
+
ActiveSupport.on_load(:active_record_postgresqladapter) do
|
83
|
+
ActiveRecord::Base.time_zone_aware_types << :timestamptz
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
81
87
|
initializer "active_record.logger" do
|
82
88
|
ActiveSupport.on_load(:active_record) { self.logger ||= ::Rails.logger }
|
83
89
|
end
|
@@ -94,22 +100,6 @@ module ActiveRecord
|
|
94
100
|
end
|
95
101
|
end
|
96
102
|
|
97
|
-
initializer "active_record.database_selector" do
|
98
|
-
if options = config.active_record.database_selector
|
99
|
-
resolver = config.active_record.database_resolver
|
100
|
-
operations = config.active_record.database_resolver_context
|
101
|
-
config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
initializer "active_record.shard_selector" do
|
106
|
-
if resolver = config.active_record.shard_resolver
|
107
|
-
options = config.active_record.shard_selector || {}
|
108
|
-
|
109
|
-
config.app_middleware.use ActiveRecord::Middleware::ShardSelector, resolver, options
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
103
|
initializer "Check for cache versioning support" do
|
114
104
|
config.after_initialize do |app|
|
115
105
|
ActiveSupport.on_load(:active_record) do
|
@@ -403,23 +393,5 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
403
393
|
end
|
404
394
|
end
|
405
395
|
end
|
406
|
-
|
407
|
-
initializer "active_record.use_yaml_unsafe_load" do |app|
|
408
|
-
config.after_initialize do
|
409
|
-
unless app.config.active_record.use_yaml_unsafe_load.nil?
|
410
|
-
ActiveRecord.use_yaml_unsafe_load =
|
411
|
-
app.config.active_record.use_yaml_unsafe_load
|
412
|
-
end
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
initializer "active_record.yaml_column_permitted_classes" do |app|
|
417
|
-
config.after_initialize do
|
418
|
-
unless app.config.active_record.yaml_column_permitted_classes.nil?
|
419
|
-
ActiveRecord.yaml_column_permitted_classes =
|
420
|
-
app.config.active_record.yaml_column_permitted_classes
|
421
|
-
end
|
422
|
-
end
|
423
|
-
end
|
424
396
|
end
|
425
397
|
end
|
@@ -452,30 +452,32 @@ db_namespace = namespace :db do
|
|
452
452
|
end
|
453
453
|
|
454
454
|
namespace :schema do
|
455
|
-
desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`)"
|
455
|
+
desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`)"
|
456
456
|
task dump: :load_config do
|
457
457
|
ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
|
458
458
|
if db_config.schema_dump
|
459
459
|
ActiveRecord::Base.establish_connection(db_config)
|
460
|
-
ActiveRecord
|
460
|
+
schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
|
461
|
+
ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, schema_format)
|
461
462
|
end
|
462
463
|
end
|
463
464
|
|
464
465
|
db_namespace["schema:dump"].reenable
|
465
466
|
end
|
466
467
|
|
467
|
-
desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) into the database"
|
468
|
+
desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) into the database"
|
468
469
|
task load: [:load_config, :check_protected_environments] do
|
469
470
|
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ActiveRecord.schema_format, ENV["SCHEMA"])
|
470
471
|
end
|
471
472
|
|
472
473
|
namespace :dump do
|
473
474
|
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
474
|
-
desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) for #{name} database"
|
475
|
+
desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) for #{name} database"
|
475
476
|
task name => :load_config do
|
476
477
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env, name: name)
|
477
478
|
ActiveRecord::Base.establish_connection(db_config)
|
478
|
-
ActiveRecord
|
479
|
+
schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
|
480
|
+
ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, schema_format)
|
479
481
|
db_namespace["schema:dump:#{name}"].reenable
|
480
482
|
end
|
481
483
|
end
|
@@ -483,11 +485,12 @@ db_namespace = namespace :db do
|
|
483
485
|
|
484
486
|
namespace :load do
|
485
487
|
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
486
|
-
desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) into the #{name} database"
|
488
|
+
desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) into the #{name} database"
|
487
489
|
task name => [:load_config, :check_protected_environments] do
|
488
490
|
original_db_config = ActiveRecord::Base.connection_db_config
|
489
491
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env, name: name)
|
490
|
-
ActiveRecord
|
492
|
+
schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
|
493
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
|
491
494
|
ensure
|
492
495
|
ActiveRecord::Base.establish_connection(original_db_config) if original_db_config
|
493
496
|
end
|
@@ -545,12 +548,13 @@ db_namespace = namespace :db do
|
|
545
548
|
db_namespace["test:load_schema"].invoke
|
546
549
|
end
|
547
550
|
|
548
|
-
# desc "Recreate the test database from an existent schema file (schema.rb or structure.sql, depending on `config.active_record.schema_format`)"
|
551
|
+
# desc "Recreate the test database from an existent schema file (schema.rb or structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`)"
|
549
552
|
task load_schema: %w(db:test:purge) do
|
550
553
|
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
|
551
554
|
ActiveRecord::Schema.verbose = false
|
552
555
|
ActiveRecord::Base.configurations.configs_for(env_name: "test").each do |db_config|
|
553
|
-
ActiveRecord
|
556
|
+
schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
|
557
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
|
554
558
|
end
|
555
559
|
ensure
|
556
560
|
if should_reconnect
|
@@ -586,7 +590,8 @@ db_namespace = namespace :db do
|
|
586
590
|
should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
|
587
591
|
ActiveRecord::Schema.verbose = false
|
588
592
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "test", name: name)
|
589
|
-
ActiveRecord
|
593
|
+
schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
|
594
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
|
590
595
|
ensure
|
591
596
|
if should_reconnect
|
592
597
|
ActiveRecord::Base.establish_connection(ActiveRecord::Tasks::DatabaseTasks.env.to_sym)
|
@@ -10,10 +10,10 @@ module ActiveRecord
|
|
10
10
|
module QueryMethods
|
11
11
|
include ActiveModel::ForbiddenAttributesProtection
|
12
12
|
|
13
|
-
# WhereChain objects act as placeholder for queries in which
|
14
|
-
# In this case,
|
13
|
+
# WhereChain objects act as placeholder for queries in which +where+ does not have any parameter.
|
14
|
+
# In this case, +where+ can be chained to return a new relation.
|
15
15
|
class WhereChain
|
16
|
-
def initialize(scope)
|
16
|
+
def initialize(scope) # :nodoc:
|
17
17
|
@scope = scope
|
18
18
|
end
|
19
19
|
|
@@ -717,12 +717,26 @@ module ActiveRecord
|
|
717
717
|
# === no argument
|
718
718
|
#
|
719
719
|
# If no argument is passed, #where returns a new instance of WhereChain, that
|
720
|
-
# can be chained with #not
|
720
|
+
# can be chained with WhereChain#not, WhereChain#missing, or WhereChain#associated.
|
721
|
+
#
|
722
|
+
# Chaining with WhereChain#not:
|
721
723
|
#
|
722
724
|
# User.where.not(name: "Jon")
|
723
725
|
# # SELECT * FROM users WHERE name != 'Jon'
|
724
726
|
#
|
725
|
-
#
|
727
|
+
# Chaining with WhereChain#associated:
|
728
|
+
#
|
729
|
+
# Post.where.associated(:author)
|
730
|
+
# # SELECT "posts".* FROM "posts"
|
731
|
+
# # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
732
|
+
# # WHERE "authors"."id" IS NOT NULL
|
733
|
+
#
|
734
|
+
# Chaining with WhereChain#missing:
|
735
|
+
#
|
736
|
+
# Post.where.missing(:author)
|
737
|
+
# # SELECT "posts".* FROM "posts"
|
738
|
+
# # LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
739
|
+
# # WHERE "authors"."id" IS NULL
|
726
740
|
#
|
727
741
|
# === blank condition
|
728
742
|
#
|
@@ -1202,6 +1216,8 @@ module ActiveRecord
|
|
1202
1216
|
# # SELECT "users"."name" FROM "users" /* selecting */ /* user */ /* names */
|
1203
1217
|
#
|
1204
1218
|
# The SQL block comment delimiters, "/*" and "*/", will be added automatically.
|
1219
|
+
#
|
1220
|
+
# Some escaping is performed, however untrusted user input should not be used.
|
1205
1221
|
def annotate(*args)
|
1206
1222
|
check_if_method_has_arguments!(__callee__, args)
|
1207
1223
|
spawn.annotate!(*args)
|
@@ -146,11 +146,13 @@ module ActiveRecord
|
|
146
146
|
end
|
147
147
|
elsif default_scopes.any?
|
148
148
|
evaluate_default_scope do
|
149
|
-
default_scopes.inject(relation) do |
|
149
|
+
default_scopes.inject(relation) do |combined_scope, scope_obj|
|
150
150
|
if execute_scope?(all_queries, scope_obj)
|
151
151
|
scope = scope_obj.scope.respond_to?(:to_proc) ? scope_obj.scope : scope_obj.scope.method(:call)
|
152
152
|
|
153
|
-
|
153
|
+
combined_scope.instance_exec(&scope) || combined_scope
|
154
|
+
else
|
155
|
+
combined_scope
|
154
156
|
end
|
155
157
|
end
|
156
158
|
end
|
@@ -97,7 +97,7 @@ module ActiveRecord
|
|
97
97
|
|
98
98
|
# Returns a signed id that's generated using a preconfigured +ActiveSupport::MessageVerifier+ instance.
|
99
99
|
# This signed id is tamper proof, so it's safe to send in an email or otherwise share with the outside world.
|
100
|
-
# It can
|
100
|
+
# It can furthermore be set to expire (the default is not to expire), and scoped down with a specific purpose.
|
101
101
|
# If the expiration date has been exceeded before +find_signed+ is called, the id won't find the designated
|
102
102
|
# record. If a purpose is set, this too must match.
|
103
103
|
#
|
data/lib/active_record/store.rb
CHANGED
@@ -59,7 +59,7 @@ module ActiveRecord
|
|
59
59
|
# u.color = 'green'
|
60
60
|
# u.color_changed? # => true
|
61
61
|
# u.color_was # => 'black'
|
62
|
-
# u.color_change # => ['black', '
|
62
|
+
# u.color_change # => ['black', 'green']
|
63
63
|
#
|
64
64
|
# # Add additional accessors to an existing store through store_accessor
|
65
65
|
# class SuperUser < User
|
@@ -268,7 +268,7 @@ module ActiveRecord
|
|
268
268
|
end
|
269
269
|
|
270
270
|
def dump(obj)
|
271
|
-
@coder.dump
|
271
|
+
@coder.dump as_regular_hash(obj)
|
272
272
|
end
|
273
273
|
|
274
274
|
def load(yaml)
|
@@ -285,6 +285,11 @@ module ActiveRecord
|
|
285
285
|
ActiveSupport::HashWithIndifferentAccess.new
|
286
286
|
end
|
287
287
|
end
|
288
|
+
|
289
|
+
private
|
290
|
+
def as_regular_hash(obj)
|
291
|
+
obj.respond_to?(:to_hash) ? obj.to_hash : {}
|
292
|
+
end
|
288
293
|
end
|
289
294
|
end
|
290
295
|
end
|
@@ -137,7 +137,7 @@ module ActiveRecord
|
|
137
137
|
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
138
138
|
spec_name = payload[:spec_name] if payload.key?(:spec_name)
|
139
139
|
shard = payload[:shard] if payload.key?(:shard)
|
140
|
-
setup_shared_connection_pool
|
140
|
+
setup_shared_connection_pool if ActiveRecord.legacy_connection_handling
|
141
141
|
|
142
142
|
if spec_name
|
143
143
|
begin
|
@@ -146,10 +146,14 @@ module ActiveRecord
|
|
146
146
|
connection = nil
|
147
147
|
end
|
148
148
|
|
149
|
-
if connection
|
150
|
-
|
151
|
-
|
152
|
-
|
149
|
+
if connection
|
150
|
+
setup_shared_connection_pool unless ActiveRecord.legacy_connection_handling
|
151
|
+
|
152
|
+
if !@fixture_connections.include?(connection)
|
153
|
+
connection.begin_transaction joinable: false, _lazy: false
|
154
|
+
connection.pool.lock_thread = true if lock_threads
|
155
|
+
@fixture_connections << connection
|
156
|
+
end
|
153
157
|
end
|
154
158
|
end
|
155
159
|
end
|
data/lib/active_record.rb
CHANGED
@@ -347,12 +347,20 @@ module ActiveRecord
|
|
347
347
|
singleton_class.attr_accessor :use_yaml_unsafe_load
|
348
348
|
self.use_yaml_unsafe_load = false
|
349
349
|
|
350
|
+
##
|
351
|
+
# :singleton-method:
|
352
|
+
# Application configurable boolean that denotes whether or not to raise
|
353
|
+
# an exception when the PostgreSQLAdapter is provided with an integer that
|
354
|
+
# is wider than signed 64bit representation
|
355
|
+
singleton_class.attr_accessor :raise_int_wider_than_64bit
|
356
|
+
self.raise_int_wider_than_64bit = true
|
357
|
+
|
350
358
|
##
|
351
359
|
# :singleton-method:
|
352
360
|
# Application configurable array that provides additional permitted classes
|
353
361
|
# to Psych safe_load in the YAML Coder
|
354
362
|
singleton_class.attr_accessor :yaml_column_permitted_classes
|
355
|
-
self.yaml_column_permitted_classes = []
|
363
|
+
self.yaml_column_permitted_classes = [Symbol]
|
356
364
|
|
357
365
|
def self.eager_load!
|
358
366
|
super
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.
|
4
|
+
version: 7.0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 7.0.
|
19
|
+
version: 7.0.4.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 7.0.
|
26
|
+
version: 7.0.4.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activemodel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - '='
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 7.0.
|
33
|
+
version: 7.0.4.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - '='
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 7.0.
|
40
|
+
version: 7.0.4.1
|
41
41
|
description: Databases on Rails. Build a persistent domain model by mapping database
|
42
42
|
tables to Ruby classes. Strong conventions for associations, validations, aggregations,
|
43
43
|
migrations, and testing come baked-in.
|
@@ -434,10 +434,10 @@ licenses:
|
|
434
434
|
- MIT
|
435
435
|
metadata:
|
436
436
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
437
|
-
changelog_uri: https://github.com/rails/rails/blob/v7.0.
|
438
|
-
documentation_uri: https://api.rubyonrails.org/v7.0.
|
437
|
+
changelog_uri: https://github.com/rails/rails/blob/v7.0.4.1/activerecord/CHANGELOG.md
|
438
|
+
documentation_uri: https://api.rubyonrails.org/v7.0.4.1/
|
439
439
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
440
|
-
source_code_uri: https://github.com/rails/rails/tree/v7.0.
|
440
|
+
source_code_uri: https://github.com/rails/rails/tree/v7.0.4.1/activerecord
|
441
441
|
rubygems_mfa_required: 'true'
|
442
442
|
post_install_message:
|
443
443
|
rdoc_options:
|
@@ -456,7 +456,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
456
456
|
- !ruby/object:Gem::Version
|
457
457
|
version: '0'
|
458
458
|
requirements: []
|
459
|
-
rubygems_version: 3.
|
459
|
+
rubygems_version: 3.4.3
|
460
460
|
signing_key:
|
461
461
|
specification_version: 4
|
462
462
|
summary: Object-relational mapper framework (part of Rails).
|