activerecord 7.1.1 → 7.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +177 -0
  3. data/README.rdoc +1 -0
  4. data/lib/active_record/associations/association.rb +2 -1
  5. data/lib/active_record/associations/preloader/association.rb +4 -1
  6. data/lib/active_record/associations.rb +15 -15
  7. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  8. data/lib/active_record/attribute_methods/dirty.rb +13 -9
  9. data/lib/active_record/attribute_methods.rb +1 -1
  10. data/lib/active_record/callbacks.rb +2 -2
  11. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +11 -8
  12. data/lib/active_record/connection_adapters/abstract/database_statements.rb +4 -2
  13. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -1
  14. data/lib/active_record/connection_adapters/abstract_adapter.rb +13 -4
  15. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +3 -0
  16. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +4 -1
  17. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  18. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -5
  19. data/lib/active_record/connection_adapters/postgresql_adapter.rb +32 -33
  20. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +10 -3
  21. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +1 -0
  22. data/lib/active_record/connection_adapters/trilogy_adapter.rb +9 -1
  23. data/lib/active_record/connection_handling.rb +1 -1
  24. data/lib/active_record/core.rb +41 -7
  25. data/lib/active_record/delegated_type.rb +1 -1
  26. data/lib/active_record/encryption/encryptable_record.rb +7 -1
  27. data/lib/active_record/encryption/encrypted_attribute_type.rb +4 -0
  28. data/lib/active_record/encryption/extended_deterministic_queries.rb +0 -15
  29. data/lib/active_record/enum.rb +6 -9
  30. data/lib/active_record/errors.rb +5 -4
  31. data/lib/active_record/fixtures.rb +16 -0
  32. data/lib/active_record/future_result.rb +1 -0
  33. data/lib/active_record/gem_version.rb +1 -1
  34. data/lib/active_record/insert_all.rb +3 -3
  35. data/lib/active_record/internal_metadata.rb +1 -1
  36. data/lib/active_record/middleware/database_selector.rb +1 -1
  37. data/lib/active_record/migration/compatibility.rb +8 -0
  38. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  39. data/lib/active_record/migration.rb +9 -5
  40. data/lib/active_record/model_schema.rb +5 -5
  41. data/lib/active_record/nested_attributes.rb +3 -3
  42. data/lib/active_record/normalization.rb +8 -0
  43. data/lib/active_record/persistence.rb +4 -3
  44. data/lib/active_record/promise.rb +1 -1
  45. data/lib/active_record/railties/controller_runtime.rb +2 -1
  46. data/lib/active_record/railties/databases.rake +5 -5
  47. data/lib/active_record/reflection.rb +13 -1
  48. data/lib/active_record/relation/calculations.rb +28 -1
  49. data/lib/active_record/relation/delegation.rb +1 -1
  50. data/lib/active_record/relation.rb +18 -3
  51. data/lib/active_record/runtime_registry.rb +15 -1
  52. data/lib/active_record/schema_migration.rb +1 -1
  53. data/lib/active_record/secure_token.rb +1 -1
  54. data/lib/active_record/tasks/database_tasks.rb +5 -5
  55. data/lib/arel/nodes/homogeneous_in.rb +1 -1
  56. metadata +10 -9
@@ -284,8 +284,10 @@ module ActiveRecord
284
284
 
285
285
  # Computes the table name, (re)sets it internally, and returns it.
286
286
  def reset_table_name # :nodoc:
287
- self.table_name = if abstract_class?
288
- superclass == Base ? nil : superclass.table_name
287
+ self.table_name = if self == Base
288
+ nil
289
+ elsif abstract_class?
290
+ superclass.table_name
289
291
  elsif superclass.abstract_class?
290
292
  superclass.table_name || compute_table_name
291
293
  else
@@ -467,7 +469,7 @@ module ActiveRecord
467
469
  end
468
470
 
469
471
  # Returns the column object for the named attribute.
470
- # Returns an +ActiveRecord::ConnectionAdapters::NullColumn+ if the
472
+ # Returns an ActiveRecord::ConnectionAdapters::NullColumn if the
471
473
  # named attribute does not exist.
472
474
  #
473
475
  # class Person < ActiveRecord::Base
@@ -627,8 +629,6 @@ module ActiveRecord
627
629
  )
628
630
  alias_attribute :id_value, :id if name == "id"
629
631
  end
630
-
631
- super
632
632
  end
633
633
 
634
634
  # Guesses the table name, but does not decorate it with prefix and suffix information.
@@ -307,7 +307,7 @@ module ActiveRecord
307
307
  # [:allow_destroy]
308
308
  # If true, destroys any members from the attributes hash with a
309
309
  # <tt>_destroy</tt> key and a value that evaluates to +true+
310
- # (e.g. 1, '1', true, or 'true'). This option is off by default.
310
+ # (e.g. 1, '1', true, or 'true'). This option is false by default.
311
311
  # [:reject_if]
312
312
  # Allows you to specify a Proc or a Symbol pointing to a method
313
313
  # that checks whether a record should be built for a certain attribute
@@ -332,11 +332,11 @@ module ActiveRecord
332
332
  # nested attributes are going to be used when an associated record already
333
333
  # exists. In general, an existing record may either be updated with the
334
334
  # new set of attribute values or be replaced by a wholly new record
335
- # containing those values. By default the +:update_only+ option is +false+
335
+ # containing those values. By default the +:update_only+ option is false
336
336
  # and the nested attributes are used to update the existing record only
337
337
  # if they include the record's <tt>:id</tt> value. Otherwise a new
338
338
  # record will be instantiated and used to replace the existing one.
339
- # However if the +:update_only+ option is +true+, the nested attributes
339
+ # However if the +:update_only+ option is true, the nested attributes
340
340
  # are used to update the record's attributes always, regardless of
341
341
  # whether the <tt>:id</tt> is present. The option is ignored for collection
342
342
  # associations.
@@ -49,6 +49,14 @@ module ActiveRecord # :nodoc:
49
49
  # By default, the normalization will not be applied to +nil+ values. This
50
50
  # behavior can be changed with the +:apply_to_nil+ option.
51
51
  #
52
+ # Be aware that if your app was created before Rails 7.1, and your app
53
+ # marshals instances of the targeted model (for example, when caching),
54
+ # then you should set ActiveRecord.marshalling_format_version to +7.1+ or
55
+ # higher via either <tt>config.load_defaults 7.1</tt> or
56
+ # <tt>config.active_record.marshalling_format_version = 7.1</tt>.
57
+ # Otherwise, +Marshal+ may attempt to serialize the normalization +Proc+
58
+ # and raise +TypeError+.
59
+ #
52
60
  # ==== Options
53
61
  #
54
62
  # * +:with+ - Any callable object that accepts the attribute's value as
@@ -115,7 +115,7 @@ module ActiveRecord
115
115
  # ==== Options
116
116
  #
117
117
  # [:returning]
118
- # (PostgreSQL only) An array of attributes to return for all successfully
118
+ # (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
119
119
  # inserted records, which by default is the primary key.
120
120
  # Pass <tt>returning: %w[ id name ]</tt> for both id and name
121
121
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
@@ -205,7 +205,7 @@ module ActiveRecord
205
205
  # ==== Options
206
206
  #
207
207
  # [:returning]
208
- # (PostgreSQL only) An array of attributes to return for all successfully
208
+ # (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
209
209
  # inserted records, which by default is the primary key.
210
210
  # Pass <tt>returning: %w[ id name ]</tt> for both id and name
211
211
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
@@ -271,7 +271,7 @@ module ActiveRecord
271
271
  # ==== Options
272
272
  #
273
273
  # [:returning]
274
- # (PostgreSQL only) An array of attributes to return for all successfully
274
+ # (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
275
275
  # inserted records, which by default is the primary key.
276
276
  # Pass <tt>returning: %w[ id name ]</tt> for both id and name
277
277
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
@@ -1076,6 +1076,7 @@ module ActiveRecord
1076
1076
  end
1077
1077
 
1078
1078
  @association_cache = fresh_object.instance_variable_get(:@association_cache)
1079
+ @association_cache.each_value { |association| association.owner = self }
1079
1080
  @attributes = fresh_object.instance_variable_get(:@attributes)
1080
1081
  @new_record = false
1081
1082
  @previously_new_record = false
@@ -31,7 +31,7 @@ module ActiveRecord
31
31
  # Returns a new +ActiveRecord::Promise+ that will apply the passed block
32
32
  # when the value is accessed:
33
33
  #
34
- # Post.async_pluck(:title).then { |title| title.upcase }.value
34
+ # Post.async_pick(:title).then { |title| title.upcase }.value
35
35
  # # => "POST TITLE"
36
36
  def then(&block)
37
37
  Promise.new(@future_result, @block ? @block >> block : block)
@@ -37,9 +37,10 @@ module ActiveRecord
37
37
  db_rt_before_render = ActiveRecord::RuntimeRegistry.reset
38
38
  self.db_runtime = (db_runtime || 0) + db_rt_before_render
39
39
  runtime = super
40
+ queries_rt = ActiveRecord::RuntimeRegistry.sql_runtime - ActiveRecord::RuntimeRegistry.async_sql_runtime
40
41
  db_rt_after_render = ActiveRecord::RuntimeRegistry.reset
41
42
  self.db_runtime += db_rt_after_render
42
- runtime - db_rt_after_render
43
+ runtime - queries_rt
43
44
  else
44
45
  super
45
46
  end
@@ -195,7 +195,7 @@ db_namespace = namespace :db do
195
195
 
196
196
  namespace :up do
197
197
  ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
198
- desc 'Run the "up" on #{name} database for a given migration VERSION.'
198
+ desc "Run the \"up\" on #{name} database for a given migration VERSION."
199
199
  task name => :load_config do
200
200
  raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
201
201
 
@@ -204,7 +204,7 @@ db_namespace = namespace :db do
204
204
  conn.migration_context.run(:up, ActiveRecord::Tasks::DatabaseTasks.target_version)
205
205
  end
206
206
 
207
- db_namespace["_dump"].invoke
207
+ db_namespace["_dump:#{name}"].invoke
208
208
  end
209
209
  end
210
210
  end
@@ -226,7 +226,7 @@ db_namespace = namespace :db do
226
226
 
227
227
  namespace :down do
228
228
  ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
229
- desc 'Run the "down" on #{name} database for a given migration VERSION.'
229
+ desc "Run the \"down\" on #{name} database for a given migration VERSION."
230
230
  task name => :load_config do
231
231
  raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
232
232
 
@@ -235,7 +235,7 @@ db_namespace = namespace :db do
235
235
  conn.migration_context.run(:down, ActiveRecord::Tasks::DatabaseTasks.target_version)
236
236
  end
237
237
 
238
- db_namespace["_dump"].invoke
238
+ db_namespace["_dump:#{name}"].invoke
239
239
  end
240
240
  end
241
241
  end
@@ -269,7 +269,7 @@ db_namespace = namespace :db do
269
269
  conn.migration_context.rollback(step)
270
270
  end
271
271
 
272
- db_namespace["_dump"].invoke
272
+ db_namespace["_dump:#{name}"].invoke
273
273
  end
274
274
  end
275
275
  end
@@ -382,6 +382,7 @@ module ActiveRecord
382
382
  @klass = options[:anonymous_class]
383
383
  @plural_name = active_record.pluralize_table_names ?
384
384
  name.to_s.pluralize : name.to_s
385
+ validate_reflection!
385
386
  end
386
387
 
387
388
  def autosave=(autosave)
@@ -433,6 +434,17 @@ module ActiveRecord
433
434
  def derive_class_name
434
435
  name.to_s.camelize
435
436
  end
437
+
438
+ def validate_reflection!
439
+ return unless options[:foreign_key].is_a?(Array)
440
+
441
+ message = <<~MSG.squish
442
+ Passing #{options[:foreign_key]} array to :foreign_key option
443
+ on the #{active_record}##{name} association is not supported.
444
+ Use the query_constraints: #{options[:foreign_key]} option instead to represent a composite foreign key.
445
+ MSG
446
+ raise ArgumentError, message
447
+ end
436
448
  end
437
449
 
438
450
  # Holds all the metadata about an aggregation as it was specified in the
@@ -858,7 +870,7 @@ module ActiveRecord
858
870
  def association_primary_key(klass = nil)
859
871
  if primary_key = options[:primary_key]
860
872
  @association_primary_key ||= -primary_key.to_s
861
- elsif !polymorphic? && ((klass || self.klass).has_query_constraints? || options[:query_constraints])
873
+ elsif (klass || self.klass).has_query_constraints? || options[:query_constraints]
862
874
  (klass || self.klass).composite_query_constraints_list
863
875
  elsif (klass || self.klass).composite_primary_key?
864
876
  # If klass has composite primary key of shape [:<tenant_key>, :id], infer primary_key as :id
@@ -81,6 +81,16 @@ module ActiveRecord
81
81
  #
82
82
  # Note: not all valid {Relation#select}[rdoc-ref:QueryMethods#select] expressions are valid #count expressions. The specifics differ
83
83
  # between databases. In invalid cases, an error from the database is thrown.
84
+ #
85
+ # When given a block, loads all records in the relation, if the relation
86
+ # hasn't been loaded yet. Calls the block with each record in the relation.
87
+ # Returns the number of records for which the block returns a truthy value.
88
+ #
89
+ # Person.count { |person| person.age > 21 }
90
+ # # => counts the number of people older that 21
91
+ #
92
+ # Note: If there are a lot of records in the relation, loading all records
93
+ # could result in performance issues.
84
94
  def count(column_name = nil)
85
95
  if block_given?
86
96
  unless column_name.nil?
@@ -148,6 +158,17 @@ module ActiveRecord
148
158
  # #calculate for examples with options.
149
159
  #
150
160
  # Person.sum(:age) # => 4562
161
+ #
162
+ # When given a block, loads all records in the relation, if the relation
163
+ # hasn't been loaded yet. Calls the block with each record in the relation.
164
+ # Returns the sum of +initial_value_or_column+ and the block return
165
+ # values:
166
+ #
167
+ # Person.sum { |person| person.age } # => 4562
168
+ # Person.sum(1000) { |person| person.age } # => 5562
169
+ #
170
+ # Note: If there are a lot of records in the relation, loading all records
171
+ # could result in performance issues.
151
172
  def sum(initial_value_or_column = 0, &block)
152
173
  if block_given?
153
174
  map(&block).sum(initial_value_or_column)
@@ -260,7 +281,13 @@ module ActiveRecord
260
281
  #
261
282
  # See also #ids.
262
283
  def pluck(*column_names)
263
- return [] if @none
284
+ if @none
285
+ if @async
286
+ return Promise::Complete.new([])
287
+ else
288
+ return []
289
+ end
290
+ end
264
291
 
265
292
  if loaded? && all_attributes?(column_names)
266
293
  result = records.pluck(*column_names)
@@ -102,7 +102,7 @@ module ActiveRecord
102
102
  :to_sentence, :to_fs, :to_formatted_s, :as_json,
103
103
  :shuffle, :split, :slice, :index, :rindex, to: :records
104
104
 
105
- delegate :primary_key, :connection, to: :klass
105
+ delegate :primary_key, :connection, :transaction, to: :klass
106
106
 
107
107
  module ClassSpecificRelation # :nodoc:
108
108
  extend ActiveSupport::Concern
@@ -164,8 +164,8 @@ module ActiveRecord
164
164
  #
165
165
  # If creation failed because of a unique constraint, this method will
166
166
  # assume it encountered a race condition and will try finding the record
167
- # once more If somehow the second find still find no record because a
168
- # concurrent DELETE happened, it will then raise an
167
+ # once more. If somehow the second find still does not find a record
168
+ # because a concurrent DELETE happened, it will then raise an
169
169
  # ActiveRecord::RecordNotFound exception.
170
170
  #
171
171
  # Please note <b>this method is not atomic</b>, it runs first a SELECT,
@@ -291,6 +291,11 @@ module ActiveRecord
291
291
  end
292
292
 
293
293
  # Returns true if there are no records.
294
+ #
295
+ # When a pattern argument is given, this method checks whether elements in
296
+ # the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
297
+ #
298
+ # posts.none?(Comment) # => true or false
294
299
  def none?(*args)
295
300
  return true if @none
296
301
 
@@ -299,6 +304,11 @@ module ActiveRecord
299
304
  end
300
305
 
301
306
  # Returns true if there are any records.
307
+ #
308
+ # When a pattern argument is given, this method checks whether elements in
309
+ # the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
310
+ #
311
+ # posts.any?(Post) # => true or false
302
312
  def any?(*args)
303
313
  return false if @none
304
314
 
@@ -307,6 +317,11 @@ module ActiveRecord
307
317
  end
308
318
 
309
319
  # Returns true if there is exactly one record.
320
+ #
321
+ # When a pattern argument is given, this method checks whether elements in
322
+ # the Enumerable match the pattern via the case-equality operator (<tt>===</tt>).
323
+ #
324
+ # posts.one?(Post) # => true or false
310
325
  def one?(*args)
311
326
  return false if @none
312
327
 
@@ -960,7 +975,7 @@ module ActiveRecord
960
975
  def exec_main_query(async: false)
961
976
  if @none
962
977
  if async
963
- return Promise::Complete.new([])
978
+ return FutureResult::Complete.new([])
964
979
  else
965
980
  return []
966
981
  end
@@ -17,13 +17,27 @@ module ActiveRecord
17
17
  ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime] = runtime
18
18
  end
19
19
 
20
+ def async_sql_runtime
21
+ ActiveSupport::IsolatedExecutionState[:active_record_async_sql_runtime] ||= 0.0
22
+ end
23
+
24
+ def async_sql_runtime=(runtime)
25
+ ActiveSupport::IsolatedExecutionState[:active_record_async_sql_runtime] = runtime
26
+ end
27
+
20
28
  def reset
21
29
  rt, self.sql_runtime = sql_runtime, 0.0
30
+ self.async_sql_runtime = 0.0
22
31
  rt
23
32
  end
24
33
  end
25
34
  end
26
35
 
27
36
  ActiveSupport::Notifications.monotonic_subscribe("sql.active_record") do |name, start, finish, id, payload|
28
- ActiveRecord::RuntimeRegistry.sql_runtime += (finish - start) * 1_000.0
37
+ runtime = (finish - start) * 1_000.0
38
+
39
+ if payload[:async]
40
+ ActiveRecord::RuntimeRegistry.async_sql_runtime += (runtime - payload[:lock_wait])
41
+ end
42
+ ActiveRecord::RuntimeRegistry.sql_runtime += runtime
29
43
  end
@@ -6,7 +6,7 @@ module ActiveRecord
6
6
  # number is inserted in to the schema migrations table so it doesn't need
7
7
  # to be executed the next time.
8
8
  class SchemaMigration # :nodoc:
9
- class NullSchemaMigration
9
+ class NullSchemaMigration # :nodoc:
10
10
  end
11
11
 
12
12
  attr_reader :connection, :arel_table
@@ -53,7 +53,7 @@ module ActiveRecord
53
53
  define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token(length: length) }
54
54
  set_callback on, on == :initialize ? :after : :before do
55
55
  if new_record? && !query_attribute(attribute)
56
- write_attribute(attribute, self.class.generate_unique_secure_token(length: length))
56
+ send("#{attribute}=", self.class.generate_unique_secure_token(length: length))
57
57
  end
58
58
  end
59
59
  end
@@ -125,11 +125,11 @@ module ActiveRecord
125
125
  end
126
126
 
127
127
  def create_all
128
- db_config = migration_connection.pool.db_config
129
-
130
- each_local_configuration { |db_config| create(db_config) }
131
-
132
- migration_class.establish_connection(db_config)
128
+ each_local_configuration do |db_config|
129
+ with_temporary_connection(db_config) do
130
+ create(db_config)
131
+ end
132
+ end
133
133
  end
134
134
 
135
135
  def setup_initial_database_yaml # :nodoc:
@@ -48,7 +48,7 @@ module Arel # :nodoc: all
48
48
  end
49
49
 
50
50
  def proc_for_binds
51
- -> value { ActiveModel::Attribute.with_cast_value(attribute.name, value, attribute.type_caster) }
51
+ -> value { ActiveModel::Attribute.with_cast_value(attribute.name, value, ActiveModel::Type.default_value) }
52
52
  end
53
53
 
54
54
  def fetch_attribute(&block)
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.1.1
4
+ version: 7.1.3
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: 2023-10-11 00:00:00.000000000 Z
11
+ date: 2024-01-16 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.1.1
19
+ version: 7.1.3
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.1.1
26
+ version: 7.1.3
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.1.1
33
+ version: 7.1.3
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.1.1
40
+ version: 7.1.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: timeout
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -279,6 +279,7 @@ files:
279
279
  - lib/active_record/migration/default_strategy.rb
280
280
  - lib/active_record/migration/execution_strategy.rb
281
281
  - lib/active_record/migration/join_table.rb
282
+ - lib/active_record/migration/pending_migration_connection.rb
282
283
  - lib/active_record/model_schema.rb
283
284
  - lib/active_record/nested_attributes.rb
284
285
  - lib/active_record/no_touching.rb
@@ -469,10 +470,10 @@ licenses:
469
470
  - MIT
470
471
  metadata:
471
472
  bug_tracker_uri: https://github.com/rails/rails/issues
472
- changelog_uri: https://github.com/rails/rails/blob/v7.1.1/activerecord/CHANGELOG.md
473
- documentation_uri: https://api.rubyonrails.org/v7.1.1/
473
+ changelog_uri: https://github.com/rails/rails/blob/v7.1.3/activerecord/CHANGELOG.md
474
+ documentation_uri: https://api.rubyonrails.org/v7.1.3/
474
475
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
475
- source_code_uri: https://github.com/rails/rails/tree/v7.1.1/activerecord
476
+ source_code_uri: https://github.com/rails/rails/tree/v7.1.3/activerecord
476
477
  rubygems_mfa_required: 'true'
477
478
  post_install_message:
478
479
  rdoc_options: