activerecord 7.1.4.1 → 7.1.5

Sign up to get free protection for your applications and to get access to all the features.
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: