activerecord 7.0.3.1 → 7.0.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -0
  3. data/lib/active_record/associations/collection_association.rb +0 -1
  4. data/lib/active_record/associations/collection_proxy.rb +1 -1
  5. data/lib/active_record/associations/has_many_association.rb +7 -4
  6. data/lib/active_record/associations/join_dependency.rb +17 -13
  7. data/lib/active_record/associations.rb +6 -6
  8. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -0
  9. data/lib/active_record/coders/yaml_column.rb +11 -5
  10. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +5 -1
  11. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
  12. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -2
  13. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -1
  14. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  15. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +1 -1
  16. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +7 -2
  17. data/lib/active_record/delegated_type.rb +1 -1
  18. data/lib/active_record/encryption/message.rb +1 -1
  19. data/lib/active_record/encryption/properties.rb +1 -1
  20. data/lib/active_record/gem_version.rb +2 -2
  21. data/lib/active_record/middleware/database_selector.rb +1 -1
  22. data/lib/active_record/model_schema.rb +21 -9
  23. data/lib/active_record/railtie.rb +6 -34
  24. data/lib/active_record/railties/databases.rake +15 -10
  25. data/lib/active_record/relation/query_methods.rb +19 -5
  26. data/lib/active_record/relation.rb +1 -0
  27. data/lib/active_record/scoping/default.rb +4 -2
  28. data/lib/active_record/signed_id.rb +1 -1
  29. data/lib/active_record/store.rb +7 -2
  30. data/lib/active_record/test_fixtures.rb +9 -5
  31. data/lib/active_record.rb +1 -1
  32. metadata +9 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3f2f45fa92947b78ba64cfc800a729cfcab5b893255efef679b686a37c50cd00
4
- data.tar.gz: 2bcca713bf8426cf4ffd22e1b832cde62a6cd6caad0f1f9b19996916e88922d5
3
+ metadata.gz: 18986b8f256d988204ff7b48287980a88e138a4280d637cf28310e551082987d
4
+ data.tar.gz: 8054f80c87f48a264d08f006b789e2c3680155e0ed7fb5a5698d962f7ff0d8bb
5
5
  SHA512:
6
- metadata.gz: 17fdc443b9f36e8dcba05e56b6c07e88e97266f7c12accb8ac084b37dbf2c134a696fc57b71171fc488ed10fc72fba952672960b7507d14762a1a41f25623df1
7
- data.tar.gz: 4dc59bd725e08e3cdf63d5145f2038f6e5c65b5eb40e611a18ef422c516543aa2acfbc893b68f25f39d304111bafd70a131928c4c1e0692e4274e5fdb1567e53
6
+ metadata.gz: 8a01f7c0f730da3cfc0bfcda6f7c9a2e3f4d2747137f87175671d79021643f09f34fcf373cb400f247159d6551589f51de73241f10ac3373159865db6e04f0fc
7
+ data.tar.gz: a4aa9659e71f1e8c11914727eacd07061128f8d68b0f609c08b272025c9923419a3a58f6d789da6a467258cad69795e3e0aa265f34ffcce4b39d8bd0cb5d8386
data/CHANGELOG.md CHANGED
@@ -1,3 +1,100 @@
1
+ ## Rails 7.0.4 (September 09, 2022) ##
2
+
3
+ * Symbol is allowed by default for YAML columns
4
+
5
+ *Étienne Barrié*
6
+
7
+ * Fix `ActiveRecord::Store` to serialize as a regular Hash
8
+
9
+ Previously it would serialize as an `ActiveSupport::HashWithIndifferentAccess`
10
+ which is wasteful and cause problem with YAML safe_load.
11
+
12
+ *Jean Boussier*
13
+
14
+ * Add `timestamptz` as a time zone aware type for PostgreSQL
15
+
16
+ This is required for correctly parsing `timestamp with time zone` values in your database.
17
+
18
+ If you don't want this, you can opt out by adding this initializer:
19
+
20
+ ```ruby
21
+ ActiveRecord::Base.time_zone_aware_types -= [:timestamptz]
22
+ ```
23
+
24
+ *Alex Ghiculescu*
25
+
26
+ * Fix supporting timezone awareness for `tsrange` and `tstzrange` array columns.
27
+
28
+ ```ruby
29
+ # In database migrations
30
+ add_column :shops, :open_hours, :tsrange, array: true
31
+ # In app config
32
+ ActiveRecord::Base.time_zone_aware_types += [:tsrange]
33
+ # In the code times are properly converted to app time zone
34
+ Shop.create!(open_hours: [Time.current..8.hour.from_now])
35
+ ```
36
+
37
+ *Wojciech Wnętrzak*
38
+
39
+ * Resolve issue where a relation cache_version could be left stale.
40
+
41
+ Previously, when `reset` was called on a relation object it did not reset the cache_versions
42
+ ivar. This led to a confusing situation where despite having the correct data the relation
43
+ still reported a stale cache_version.
44
+
45
+ Usage:
46
+
47
+ ```ruby
48
+ developers = Developer.all
49
+ developers.cache_version
50
+
51
+ Developer.update_all(updated_at: Time.now.utc + 1.second)
52
+
53
+ developers.cache_version # Stale cache_version
54
+ developers.reset
55
+ developers.cache_version # Returns the current correct cache_version
56
+ ```
57
+
58
+ Fixes #45341.
59
+
60
+ *Austen Madden*
61
+
62
+ * Fix `load_async` when called on an association proxy.
63
+
64
+ Calling `load_async` directly an association would schedule
65
+ a query but never use it.
66
+
67
+ ```ruby
68
+ comments = post.comments.load_async # schedule a query
69
+ comments.to_a # perform an entirely new sync query
70
+ ```
71
+
72
+ Now it does use the async query, however note that it doesn't
73
+ cause the association to be loaded.
74
+
75
+ *Jean Boussier*
76
+
77
+ * Fix eager loading for models without primary keys.
78
+
79
+ *Anmol Chopra*, *Matt Lawrence*, and *Jonathan Hefner*
80
+
81
+ * `rails db:schema:{dump,load}` now checks `ENV["SCHEMA_FORMAT"]` before config
82
+
83
+ Since `rails db:structure:{dump,load}` was deprecated there wasn't a simple
84
+ way to dump a schema to both SQL and Ruby formats. You can now do this with
85
+ an environment variable. For example:
86
+
87
+ ```
88
+ SCHEMA_FORMAT=sql rake db:schema:dump
89
+ ```
90
+
91
+ *Alex Ghiculescu*
92
+
93
+ * Fix Hstore deserialize regression.
94
+
95
+ *edsharp*
96
+
97
+
1
98
  ## Rails 7.0.3.1 (July 12, 2022) ##
2
99
 
3
100
  * 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 and @target has no new records
83
- # we are certain the current target is an empty array. This is a
84
- # documented side-effect of the method that may avoid an extra SELECT.
85
- loaded! if count == 0
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
- key = aliases.column_alias(node, node.primary_key)
256
- id = row[key]
257
- if id.nil?
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
- # * <tt>firm.clients.destroy(client)</tt>
632
- # * <tt>firm.clients.destroy(*clients)</tt>
633
- # * <tt>firm.clients.destroy_all</tt>
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
- # * <tt>firm.clients.delete(client)</tt>
638
- # * <tt>firm.clients.delete(*clients)</tt>
639
- # * <tt>firm.clients.delete_all</tt>
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
- def yaml_load(payload)
49
- if !ActiveRecord.use_yaml_unsafe_load
50
- YAML.safe_load(payload, permitted_classes: ActiveRecord.yaml_column_permitted_classes, aliases: true)
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
@@ -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).match(/`#{field_name}` (.+) DEFAULT ('|\d+|[A-z]+)/)
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.scan_until(/(?<!\\)(?=")/)
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.scan_until(/(?<!\\)(?=")/)
44
+ unless value = scanner.scan(/^(\\[\\"]|[^\\"])*?(?=")/)
45
45
  raise(ArgumentError, ERROR % scanner.string.inspect)
46
46
  end
47
47
 
@@ -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: column.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 +Entry#title+, and polymorphism will provide you with the answer.
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
  #
@@ -7,7 +7,7 @@ module ActiveRecord
7
7
  # * An encrypted payload
8
8
  # * A list of unencrypted headers
9
9
  #
10
- # See +Encryptor#encrypt+
10
+ # See Encryptor#encrypt
11
11
  class Message
12
12
  attr_accessor :payload, :headers
13
13
 
@@ -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#DEFAULT_PROPERTIES+, +Key+, +Message+
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
 
@@ -9,8 +9,8 @@ module ActiveRecord
9
9
  module VERSION
10
10
  MAJOR = 7
11
11
  MINOR = 0
12
- TINY = 3
13
- PRE = "1"
12
+ TINY = 4
13
+ PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -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 libaries
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=
@@ -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::Tasks::DatabaseTasks.dump_schema(db_config)
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::Tasks::DatabaseTasks.dump_schema(db_config)
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::Tasks::DatabaseTasks.load_schema(db_config)
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::Tasks::DatabaseTasks.load_schema(db_config)
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::Tasks::DatabaseTasks.load_schema(db_config)
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 #where does not have any parameter.
14
- # In this case, #where must be chained with #not to return a new relation.
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 to return a new relation that negates the where clause.
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
- # See WhereChain for more details on #not.
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
  #
@@ -712,6 +712,7 @@ module ActiveRecord
712
712
  @to_sql = @arel = @loaded = @should_eager_load = nil
713
713
  @offsets = @take = nil
714
714
  @cache_keys = nil
715
+ @cache_versions = nil
715
716
  @records = nil
716
717
  self
717
718
  end
@@ -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 |default_scope, scope_obj|
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
- default_scope.instance_exec(&scope) || default_scope
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 further more be set to expire (the default is not to expire), and scoped down with a specific purpose.
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
  #
@@ -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', 'red']
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 self.class.as_indifferent_hash(obj)
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 && !@fixture_connections.include?(connection)
150
- connection.begin_transaction joinable: false, _lazy: false
151
- connection.pool.lock_thread = true if lock_threads
152
- @fixture_connections << connection
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
@@ -352,7 +352,7 @@ module ActiveRecord
352
352
  # Application configurable array that provides additional permitted classes
353
353
  # to Psych safe_load in the YAML Coder
354
354
  singleton_class.attr_accessor :yaml_column_permitted_classes
355
- self.yaml_column_permitted_classes = []
355
+ self.yaml_column_permitted_classes = [Symbol]
356
356
 
357
357
  def self.eager_load!
358
358
  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.3.1
4
+ version: 7.0.4
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: 2022-07-12 00:00:00.000000000 Z
11
+ date: 2022-09-09 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.3.1
19
+ version: 7.0.4
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.3.1
26
+ version: 7.0.4
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.3.1
33
+ version: 7.0.4
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.3.1
40
+ version: 7.0.4
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.3.1/activerecord/CHANGELOG.md
438
- documentation_uri: https://api.rubyonrails.org/v7.0.3.1/
437
+ changelog_uri: https://github.com/rails/rails/blob/v7.0.4/activerecord/CHANGELOG.md
438
+ documentation_uri: https://api.rubyonrails.org/v7.0.4/
439
439
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
440
- source_code_uri: https://github.com/rails/rails/tree/v7.0.3.1/activerecord
440
+ source_code_uri: https://github.com/rails/rails/tree/v7.0.4/activerecord
441
441
  rubygems_mfa_required: 'true'
442
442
  post_install_message:
443
443
  rdoc_options: