activerecord 7.1.4.1 → 7.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a200f8abed48ce6ab97abf8451e08f9178d634f1b6186b61ee4a81552e246109
4
- data.tar.gz: c379bb65f3b1819ed78702da8bb8167ca21c34a9a35d54e67bacff74ce3fefc3
3
+ metadata.gz: b45ca3fee0a501dbddff6f5513b1c6d76224df56a5826e4cdcc67bded7fe299e
4
+ data.tar.gz: a5c02ade3297c1a2aae5ddd20f51ad4bb83d53bc807b968f3253c69bb8598f9b
5
5
  SHA512:
6
- metadata.gz: 3a1564536513adb015b00aa10817bc0f672199788ede2b3ff7cef755622fde07c02c3410c6d7f223127998da69cfd2ff3033fef2615bbd778ea3f26dbdf62f1f
7
- data.tar.gz: 44838c96abc346df10cf6ad6aae9083f09a96345b53cdc78cd216a0db2c2c10a0831c66d8ce17d7e1f11a897c4d9bb8eb81b06dbc231589624565da4275f2f96
6
+ metadata.gz: e2083fba136690148693664668f35e35717ccf6116cdcf28a996e5e5b4e021f633d5c786d676c447f63423bb4b418415270214966cb0c2539569a3e0a979bd7a
7
+ data.tar.gz: 4b81f2d092784dff65738ea7f1873dbb4c72b70e2fc5cdf3b70f64d8e7e7ed0b44e108ea16966d63e49eb3efa9a0c5a396ed1b5426c6272b97fb9813186f5e29
data/CHANGELOG.md CHANGED
@@ -1,3 +1,51 @@
1
+ ## Rails 7.1.5 (October 30, 2024) ##
2
+
3
+ * Fix marshalling of unsaved associated records in 7.1 format.
4
+
5
+ The 7.1 format would only marshal associated records if the association was loaded.
6
+ But associations that would only contain unsaved records would be skipped.
7
+
8
+ *Jean Boussier*
9
+
10
+ * Fix an issue where `.left_outer_joins` used with multiple associations that have
11
+ the same child association but different parents does not join all parents.
12
+
13
+ Previously, using `.left_outer_joins` with the same child association would only join one of the parents.
14
+
15
+ Now it will correctly join both parents.
16
+
17
+ Fixes #41498.
18
+
19
+ *Garrett Blehm*
20
+
21
+ * Ensure `ActiveRecord::Encryption.config` is always ready before access.
22
+
23
+ Previously, `ActiveRecord::Encryption` configuration was deferred until `ActiveRecord::Base`
24
+ was loaded. Therefore, accessing `ActiveRecord::Encryption.config` properties before
25
+ `ActiveRecord::Base` was loaded would give incorrect results.
26
+
27
+ `ActiveRecord::Encryption` now has its own loading hook so that its configuration is set as
28
+ soon as needed.
29
+
30
+ When `ActiveRecord::Base` is loaded, even lazily, it in turn triggers the loading of
31
+ `ActiveRecord::Encryption`, thus preserving the original behavior of having its config ready
32
+ before any use of `ActiveRecord::Base`.
33
+
34
+ *Maxime Réty*
35
+
36
+ * Add `TimeZoneConverter#==` method, so objects will be properly compared by
37
+ their type, scale, limit & precision.
38
+
39
+ Address #52699.
40
+
41
+ *Ruy Rocha*
42
+
43
+
44
+ ## Rails 7.1.4.2 (October 23, 2024) ##
45
+
46
+ * No changes.
47
+
48
+
1
49
  ## Rails 7.1.4.1 (October 15, 2024) ##
2
50
 
3
51
  * No changes.
@@ -25,8 +25,9 @@ module ActiveRecord
25
25
  joins = []
26
26
  chain = []
27
27
 
28
- reflection.chain.each do |reflection|
29
- table, terminated = yield reflection
28
+ reflection_chain = reflection.chain
29
+ reflection_chain.each_with_index do |reflection, index|
30
+ table, terminated = yield reflection, reflection_chain[index..]
30
31
  @table ||= table
31
32
 
32
33
  if terminated
@@ -190,12 +190,12 @@ module ActiveRecord
190
190
  def make_constraints(parent, child, join_type)
191
191
  foreign_table = parent.table
192
192
  foreign_klass = parent.base_klass
193
- child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker) do |reflection|
194
- table, terminated = @joined_tables[reflection]
193
+ child.join_constraints(foreign_table, foreign_klass, join_type, alias_tracker) do |reflection, remaining_reflection_chain|
194
+ table, terminated = @joined_tables[remaining_reflection_chain]
195
195
  root = reflection == child.reflection
196
196
 
197
197
  if table && (!root || !terminated)
198
- @joined_tables[reflection] = [table, root] if root
198
+ @joined_tables[remaining_reflection_chain] = [table, root] if root
199
199
  next table, true
200
200
  end
201
201
 
@@ -206,7 +206,7 @@ module ActiveRecord
206
206
  root ? name : "#{name}_join"
207
207
  end
208
208
 
209
- @joined_tables[reflection] ||= [table, root] if join_type == Arel::Nodes::OuterJoin
209
+ @joined_tables[remaining_reflection_chain] ||= [table, root] if join_type == Arel::Nodes::OuterJoin
210
210
  table
211
211
  end.concat child.children.flat_map { |c| make_constraints(child, c, join_type) }
212
212
  end
@@ -32,6 +32,10 @@ module ActiveRecord
32
32
  end
33
33
  end
34
34
 
35
+ def ==(other)
36
+ other.is_a?(self.class) && __getobj__ == other.__getobj__
37
+ end
38
+
35
39
  private
36
40
  def convert_time_to_time_zone(value)
37
41
  return if value.nil?
@@ -31,7 +31,7 @@ module ActiveRecord
31
31
  # TODO: Remove when IPAddr#== compares IPAddr#prefix. See
32
32
  # https://github.com/ruby/ipaddr/issues/21
33
33
  def changed?(old_value, new_value, _new_value_before_type_cast)
34
- super || !old_value.nil? && old_value.prefix != new_value.prefix
34
+ !old_value.eql?(new_value) || !old_value.nil? && old_value.prefix != new_value.prefix
35
35
  end
36
36
 
37
37
  def cast_value(value)
@@ -247,6 +247,8 @@ module ActiveRecord
247
247
 
248
248
  # Returns the sequence name for a table's primary key or some other specified key.
249
249
  def default_sequence_name(table_name, pk = "id") # :nodoc:
250
+ return nil if pk.is_a?(Array)
251
+
250
252
  result = serial_sequence(table_name, pk)
251
253
  return nil unless result
252
254
  Utils.extract_schema_qualified_name(result).to_s
@@ -346,7 +346,7 @@ module ActiveRecord
346
346
 
347
347
  # Returns a string like 'Post(id:integer, title:string, body:text)'
348
348
  def inspect # :nodoc:
349
- if self == Base
349
+ if self == Base || singleton_class?
350
350
  super
351
351
  elsif abstract_class?
352
352
  "#{super}(abstract)"
@@ -46,7 +46,7 @@ module ActiveRecord
46
46
  attr_reader :uri
47
47
 
48
48
  def uri_parser
49
- @uri_parser ||= URI::Parser.new
49
+ @uri_parser ||= URI::RFC2396_Parser.new
50
50
  end
51
51
 
52
52
  # Converts the query parameters of the URI into a hash.
@@ -53,4 +53,6 @@ module ActiveRecord
53
53
  Cipher.eager_load!
54
54
  end
55
55
  end
56
+
57
+ ActiveSupport.run_load_hooks :active_record_encryption, Encryption
56
58
  end
@@ -247,7 +247,7 @@ module ActiveRecord
247
247
 
248
248
  attribute(name, **options) do |subtype|
249
249
  if subtype == ActiveModel::Type.default_value
250
- raise "Undeclared attribute type for enum '#{name}'. Enums must be" \
250
+ raise "Undeclared attribute type for enum '#{name}' in #{self.name}. Enums must be" \
251
251
  " backed by a database column or declared with an explicit type" \
252
252
  " via `attribute`."
253
253
  end
@@ -9,8 +9,8 @@ module ActiveRecord
9
9
  module VERSION
10
10
  MAJOR = 7
11
11
  MINOR = 1
12
- TINY = 4
13
- PRE = "1"
12
+ TINY = 5
13
+ PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -25,7 +25,10 @@ module ActiveRecord
25
25
  payload = [attributes_for_database, new_record?]
26
26
 
27
27
  cached_associations = self.class.reflect_on_all_associations.select do |reflection|
28
- association_cached?(reflection.name) && association(reflection.name).loaded?
28
+ if association_cached?(reflection.name)
29
+ association = association(reflection.name)
30
+ association.loaded? || association.target.present?
31
+ end
29
32
  end
30
33
 
31
34
  unless cached_associations.empty?
@@ -633,6 +633,7 @@ module ActiveRecord
633
633
  )
634
634
  alias_attribute :id_value, :id if name == "id"
635
635
  end
636
+ _default_attributes # Precompute to cache DB-dependent attribute types
636
637
  end
637
638
 
638
639
  # Guesses the table name, but does not decorate it with prefix and suffix information.
@@ -519,12 +519,12 @@ module ActiveRecord
519
519
  unless reject_new_record?(association_name, attributes)
520
520
  association.reader.build(attributes.except(*UNASSIGNABLE_KEYS))
521
521
  end
522
- elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes["id"].to_s }
522
+ elsif existing_record = find_record_by_id(existing_records, attributes["id"])
523
523
  unless call_reject_if(association_name, attributes)
524
524
  # Make sure we are operating on the actual object which is in the association's
525
525
  # proxy_target array (either by finding it, or adding it if not found)
526
526
  # Take into account that the proxy_target may have changed due to callbacks
527
- target_record = association.target.detect { |record| record.id.to_s == attributes["id"].to_s }
527
+ target_record = find_record_by_id(association.target, attributes["id"])
528
528
  if target_record
529
529
  existing_record = target_record
530
530
  else
@@ -612,5 +612,16 @@ module ActiveRecord
612
612
  raise RecordNotFound.new("Couldn't find #{model} with ID=#{record_id} for #{self.class.name} with ID=#{id}",
613
613
  model, "id", record_id)
614
614
  end
615
+
616
+ def find_record_by_id(records, id)
617
+ return if records.empty?
618
+
619
+ if records.first.class.composite_primary_key?
620
+ id = Array(id).map(&:to_s)
621
+ records.find { |record| Array(record.id).map(&:to_s) == id }
622
+ else
623
+ records.find { |record| record.id.to_s == id.to_s }
624
+ end
625
+ end
615
626
  end
616
627
  end
@@ -377,16 +377,19 @@ To keep using the current cache store, you can turn off cache versioning entirel
377
377
  end
378
378
 
379
379
  initializer "active_record_encryption.configuration" do |app|
380
- ActiveSupport.on_load(:active_record) do
381
- ActiveRecord::Encryption.configure \
380
+ ActiveSupport.on_load(:active_record_encryption) do
381
+ ActiveRecord::Encryption.configure(
382
382
  primary_key: app.credentials.dig(:active_record_encryption, :primary_key),
383
383
  deterministic_key: app.credentials.dig(:active_record_encryption, :deterministic_key),
384
384
  key_derivation_salt: app.credentials.dig(:active_record_encryption, :key_derivation_salt),
385
385
  **app.config.active_record.encryption
386
+ )
386
387
 
387
388
  auto_filtered_parameters = ActiveRecord::Encryption::AutoFilteredParameters.new(app)
388
389
  auto_filtered_parameters.enable if ActiveRecord::Encryption.config.add_to_filter_parameters
390
+ end
389
391
 
392
+ ActiveSupport.on_load(:active_record) do
390
393
  # Support extended queries for deterministic attributes and validations
391
394
  if ActiveRecord::Encryption.config.extend_queries
392
395
  ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
@@ -175,6 +175,7 @@ module ActiveRecord
175
175
 
176
176
  def prepare_all
177
177
  seed = false
178
+ dump_db_configs = []
178
179
 
179
180
  each_current_configuration(env) do |db_config|
180
181
  with_temporary_pool(db_config) do
@@ -197,15 +198,25 @@ module ActiveRecord
197
198
 
198
199
  each_current_environment(env) do |environment|
199
200
  db_configs_with_versions(environment).sort.each do |version, db_configs|
201
+ dump_db_configs |= db_configs
202
+
200
203
  db_configs.each do |db_config|
201
204
  with_temporary_pool(db_config) do
202
205
  migrate(version)
203
- dump_schema(db_config) if ActiveRecord.dump_schema_after_migration
204
206
  end
205
207
  end
206
208
  end
207
209
  end
208
210
 
211
+ # Dump schema for databases that were migrated.
212
+ if ActiveRecord.dump_schema_after_migration
213
+ dump_db_configs.each do |db_config|
214
+ with_temporary_pool(db_config) do
215
+ dump_schema(db_config)
216
+ end
217
+ end
218
+ end
219
+
209
220
  load_seed if seed
210
221
  end
211
222
 
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.4.1
4
+ version: 7.1.5
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: 2024-10-15 00:00:00.000000000 Z
11
+ date: 2024-10-31 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.4.1
19
+ version: 7.1.5
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.4.1
26
+ version: 7.1.5
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.4.1
33
+ version: 7.1.5
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.4.1
40
+ version: 7.1.5
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: timeout
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -470,10 +470,10 @@ licenses:
470
470
  - MIT
471
471
  metadata:
472
472
  bug_tracker_uri: https://github.com/rails/rails/issues
473
- changelog_uri: https://github.com/rails/rails/blob/v7.1.4.1/activerecord/CHANGELOG.md
474
- documentation_uri: https://api.rubyonrails.org/v7.1.4.1/
473
+ changelog_uri: https://github.com/rails/rails/blob/v7.1.5/activerecord/CHANGELOG.md
474
+ documentation_uri: https://api.rubyonrails.org/v7.1.5/
475
475
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
476
- source_code_uri: https://github.com/rails/rails/tree/v7.1.4.1/activerecord
476
+ source_code_uri: https://github.com/rails/rails/tree/v7.1.5/activerecord
477
477
  rubygems_mfa_required: 'true'
478
478
  post_install_message:
479
479
  rdoc_options: