activerecord 8.0.1 → 8.0.2

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +138 -1
  3. data/lib/active_record/associations/alias_tracker.rb +6 -4
  4. data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
  5. data/lib/active_record/attributes.rb +2 -2
  6. data/lib/active_record/autosave_association.rb +21 -11
  7. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +17 -14
  8. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +14 -9
  9. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  10. data/lib/active_record/connection_adapters/abstract_adapter.rb +39 -22
  11. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +4 -0
  12. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -1
  13. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  14. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +12 -12
  15. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
  16. data/lib/active_record/connection_adapters/postgresql_adapter.rb +7 -2
  17. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -0
  18. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +6 -1
  19. data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -1
  20. data/lib/active_record/core.rb +31 -2
  21. data/lib/active_record/counter_cache.rb +1 -1
  22. data/lib/active_record/delegated_type.rb +17 -17
  23. data/lib/active_record/future_result.rb +3 -3
  24. data/lib/active_record/gem_version.rb +1 -1
  25. data/lib/active_record/migration/command_recorder.rb +5 -2
  26. data/lib/active_record/railties/databases.rake +1 -1
  27. data/lib/active_record/relation/calculations.rb +23 -17
  28. data/lib/active_record/relation.rb +1 -1
  29. data/lib/active_record/signed_id.rb +4 -3
  30. data/lib/active_record/statement_cache.rb +2 -2
  31. data/lib/active_record/transactions.rb +5 -6
  32. data/lib/arel/collectors/bind.rb +1 -1
  33. data/lib/arel/collectors/sql_string.rb +1 -1
  34. data/lib/arel/collectors/substitute_binds.rb +2 -2
  35. data/lib/arel/nodes/binary.rb +1 -1
  36. data/lib/arel/nodes/node.rb +1 -1
  37. data/lib/arel/nodes/sql_literal.rb +1 -1
  38. data/lib/arel/visitors/to_sql.rb +1 -1
  39. metadata +10 -13
@@ -5,9 +5,8 @@ module ActiveRecord
5
5
  class PoolConfig # :nodoc:
6
6
  include MonitorMixin
7
7
 
8
- attr_reader :db_config, :role, :shard
8
+ attr_reader :db_config, :role, :shard, :connection_descriptor
9
9
  attr_writer :schema_reflection, :server_version
10
- attr_accessor :connection_class
11
10
 
12
11
  def schema_reflection
13
12
  @schema_reflection ||= SchemaReflection.new(db_config.lazy_schema_cache_path)
@@ -29,7 +28,7 @@ module ActiveRecord
29
28
  def initialize(connection_class, db_config, role, shard)
30
29
  super()
31
30
  @server_version = nil
32
- @connection_class = connection_class
31
+ self.connection_descriptor = connection_class
33
32
  @db_config = db_config
34
33
  @role = role
35
34
  @shard = shard
@@ -41,11 +40,12 @@ module ActiveRecord
41
40
  @server_version || synchronize { @server_version ||= connection.get_database_version }
42
41
  end
43
42
 
44
- def connection_name
45
- if connection_class.primary_class?
46
- "ActiveRecord::Base"
43
+ def connection_descriptor=(connection_descriptor)
44
+ case connection_descriptor
45
+ when ConnectionHandler::ConnectionDescriptor
46
+ @connection_descriptor = connection_descriptor
47
47
  else
48
- connection_class.name
48
+ @connection_descriptor = ConnectionHandler::ConnectionDescriptor.new(connection_descriptor.name, connection_descriptor.primary_class?)
49
49
  end
50
50
  end
51
51
 
@@ -308,8 +308,8 @@ module ActiveRecord
308
308
  # t.exclusion_constraint("price WITH =, availability_range WITH &&", using: :gist, name: "price_check")
309
309
  #
310
310
  # See {connection.add_exclusion_constraint}[rdoc-ref:SchemaStatements#add_exclusion_constraint]
311
- def exclusion_constraint(*args)
312
- @base.add_exclusion_constraint(name, *args)
311
+ def exclusion_constraint(...)
312
+ @base.add_exclusion_constraint(name, ...)
313
313
  end
314
314
 
315
315
  # Removes the given exclusion constraint from the table.
@@ -317,8 +317,8 @@ module ActiveRecord
317
317
  # t.remove_exclusion_constraint(name: "price_check")
318
318
  #
319
319
  # See {connection.remove_exclusion_constraint}[rdoc-ref:SchemaStatements#remove_exclusion_constraint]
320
- def remove_exclusion_constraint(*args)
321
- @base.remove_exclusion_constraint(name, *args)
320
+ def remove_exclusion_constraint(...)
321
+ @base.remove_exclusion_constraint(name, ...)
322
322
  end
323
323
 
324
324
  # Adds a unique constraint.
@@ -326,8 +326,8 @@ module ActiveRecord
326
326
  # t.unique_constraint(:position, name: 'unique_position', deferrable: :deferred, nulls_not_distinct: true)
327
327
  #
328
328
  # See {connection.add_unique_constraint}[rdoc-ref:SchemaStatements#add_unique_constraint]
329
- def unique_constraint(*args)
330
- @base.add_unique_constraint(name, *args)
329
+ def unique_constraint(...)
330
+ @base.add_unique_constraint(name, ...)
331
331
  end
332
332
 
333
333
  # Removes the given unique constraint from the table.
@@ -335,8 +335,8 @@ module ActiveRecord
335
335
  # t.remove_unique_constraint(name: "unique_position")
336
336
  #
337
337
  # See {connection.remove_unique_constraint}[rdoc-ref:SchemaStatements#remove_unique_constraint]
338
- def remove_unique_constraint(*args)
339
- @base.remove_unique_constraint(name, *args)
338
+ def remove_unique_constraint(...)
339
+ @base.remove_unique_constraint(name, ...)
340
340
  end
341
341
 
342
342
  # Validates the given constraint on the table.
@@ -345,8 +345,8 @@ module ActiveRecord
345
345
  # t.validate_constraint "price_check"
346
346
  #
347
347
  # See {connection.validate_constraint}[rdoc-ref:SchemaStatements#validate_constraint]
348
- def validate_constraint(*args)
349
- @base.validate_constraint(name, *args)
348
+ def validate_constraint(...)
349
+ @base.validate_constraint(name, ...)
350
350
  end
351
351
 
352
352
  # Validates the given check constraint on the table
@@ -355,8 +355,8 @@ module ActiveRecord
355
355
  # t.validate_check_constraint name: "price_check"
356
356
  #
357
357
  # See {connection.validate_check_constraint}[rdoc-ref:SchemaStatements#validate_check_constraint]
358
- def validate_check_constraint(*args)
359
- @base.validate_check_constraint(name, *args)
358
+ def validate_check_constraint(...)
359
+ @base.validate_check_constraint(name, ...)
360
360
  end
361
361
  end
362
362
 
@@ -22,7 +22,7 @@ module ActiveRecord
22
22
  stream.puts " # Custom types defined in this database."
23
23
  stream.puts " # Note that some types may not work with other database engines. Be careful if changing database."
24
24
  types.sort.each do |name, values|
25
- stream.puts " create_enum #{name.inspect}, #{values.split(",").inspect}"
25
+ stream.puts " create_enum #{name.inspect}, #{values.inspect}"
26
26
  end
27
27
  stream.puts
28
28
  end
@@ -349,6 +349,7 @@ module ActiveRecord
349
349
  @lock.synchronize do
350
350
  return false unless @raw_connection
351
351
  @raw_connection.query ";"
352
+ verified!
352
353
  end
353
354
  true
354
355
  rescue PG::Error
@@ -520,7 +521,7 @@ module ActiveRecord
520
521
  type.typname AS name,
521
522
  type.OID AS oid,
522
523
  n.nspname AS schema,
523
- string_agg(enum.enumlabel, ',' ORDER BY enum.enumsortorder) AS value
524
+ array_agg(enum.enumlabel ORDER BY enum.enumsortorder) AS value
524
525
  FROM pg_enum AS enum
525
526
  JOIN pg_type AS type ON (type.oid = enum.enumtypid)
526
527
  JOIN pg_namespace n ON type.typnamespace = n.oid
@@ -633,7 +634,11 @@ module ActiveRecord
633
634
  # Returns the version of the connected PostgreSQL server.
634
635
  def get_database_version # :nodoc:
635
636
  with_raw_connection do |conn|
636
- conn.server_version
637
+ version = conn.server_version
638
+ if version == 0
639
+ raise ActiveRecord::ConnectionFailed, "Could not determine PostgreSQL version"
640
+ end
641
+ version
637
642
  end
638
643
  end
639
644
  alias :postgresql_version :database_version
@@ -50,6 +50,19 @@ module ActiveRecord
50
50
  end
51
51
  end
52
52
 
53
+ def quote(value) # :nodoc:
54
+ case value
55
+ when Numeric
56
+ if value.finite?
57
+ super
58
+ else
59
+ "'#{value}'"
60
+ end
61
+ else
62
+ super
63
+ end
64
+ end
65
+
53
66
  def quote_string(s)
54
67
  ::SQLite3::Database.quote(s)
55
68
  end
@@ -207,7 +207,12 @@ module ActiveRecord
207
207
  !(@raw_connection.nil? || @raw_connection.closed?)
208
208
  end
209
209
 
210
- alias_method :active?, :connected?
210
+ def active?
211
+ if connected?
212
+ verified!
213
+ true
214
+ end
215
+ end
211
216
 
212
217
  alias :reset! :reconnect!
213
218
 
@@ -121,7 +121,7 @@ module ActiveRecord
121
121
  end
122
122
 
123
123
  def active?
124
- connected? && @lock.synchronize { @raw_connection&.ping } || false
124
+ connected? && @lock.synchronize { @raw_connection&.ping; verified! } || false
125
125
  rescue ::Trilogy::Error
126
126
  false
127
127
  end
@@ -202,6 +202,17 @@ module ActiveRecord
202
202
  false
203
203
  end
204
204
 
205
+ # Intended to behave like `.current_preventing_writes` given the class name as input.
206
+ # See PoolConfig and ConnectionHandler::ConnectionDescriptor.
207
+ def self.preventing_writes?(class_name) # :nodoc:
208
+ connected_to_stack.reverse_each do |hash|
209
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
210
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].any? { |klass| klass.name == class_name }
211
+ end
212
+
213
+ false
214
+ end
215
+
205
216
  def self.connected_to_stack # :nodoc:
206
217
  if connected_to_stack = ActiveSupport::IsolatedExecutionState[:active_record_connected_to_stack]
207
218
  connected_to_stack
@@ -727,11 +738,29 @@ module ActiveRecord
727
738
  @strict_loading_mode == :all
728
739
  end
729
740
 
730
- # Marks this record as read only.
741
+ # Prevents records from being written to the database:
742
+ #
743
+ # customer = Customer.new
744
+ # customer.readonly!
745
+ # customer.save # raises ActiveRecord::ReadOnlyRecord
731
746
  #
732
747
  # customer = Customer.first
733
748
  # customer.readonly!
734
- # customer.save # Raises an ActiveRecord::ReadOnlyRecord
749
+ # customer.update(name: 'New Name') # raises ActiveRecord::ReadOnlyRecord
750
+ #
751
+ # Read-only records cannot be deleted from the database either:
752
+ #
753
+ # customer = Customer.first
754
+ # customer.readonly!
755
+ # customer.destroy # raises ActiveRecord::ReadOnlyRecord
756
+ #
757
+ # Please, note that the objects themselves are still mutable in memory:
758
+ #
759
+ # customer = Customer.new
760
+ # customer.readonly!
761
+ # customer.name = 'New Name' # OK
762
+ #
763
+ # but you won't be able to persist the changes.
735
764
  def readonly!
736
765
  @readonly = true
737
766
  end
@@ -28,7 +28,7 @@ module ActiveRecord
28
28
  # # For the Post with id #1, reset the comments_count
29
29
  # Post.reset_counters(1, :comments)
30
30
  #
31
- # # Like above, but also touch the +updated_at+ and/or +updated_on+
31
+ # # Like above, but also touch the updated_at and/or updated_on
32
32
  # # attributes.
33
33
  # Post.reset_counters(1, :comments, touch: true)
34
34
  def reset_counters(id, *counters, touch: nil)
@@ -181,16 +181,16 @@ module ActiveRecord
181
181
  # delegated_type :entryable, types: %w[ Message Comment ], dependent: :destroy
182
182
  # end
183
183
  #
184
- # Entry#entryable_class # => +Message+ or +Comment+
185
- # Entry#entryable_name # => "message" or "comment"
186
- # Entry.messages # => Entry.where(entryable_type: "Message")
187
- # Entry#message? # => true when entryable_type == "Message"
188
- # Entry#message # => returns the message record, when entryable_type == "Message", otherwise nil
189
- # Entry#message_id # => returns entryable_id, when entryable_type == "Message", otherwise nil
190
- # Entry.comments # => Entry.where(entryable_type: "Comment")
191
- # Entry#comment? # => true when entryable_type == "Comment"
192
- # Entry#comment # => returns the comment record, when entryable_type == "Comment", otherwise nil
193
- # Entry#comment_id # => returns entryable_id, when entryable_type == "Comment", otherwise nil
184
+ # @entry.entryable_class # => Message or Comment
185
+ # @entry.entryable_name # => "message" or "comment"
186
+ # Entry.messages # => Entry.where(entryable_type: "Message")
187
+ # @entry.message? # => true when entryable_type == "Message"
188
+ # @entry.message # => returns the message record, when entryable_type == "Message", otherwise nil
189
+ # @entry.message_id # => returns entryable_id, when entryable_type == "Message", otherwise nil
190
+ # Entry.comments # => Entry.where(entryable_type: "Comment")
191
+ # @entry.comment? # => true when entryable_type == "Comment"
192
+ # @entry.comment # => returns the comment record, when entryable_type == "Comment", otherwise nil
193
+ # @entry.comment_id # => returns entryable_id, when entryable_type == "Comment", otherwise nil
194
194
  #
195
195
  # You can also declare namespaced types:
196
196
  #
@@ -199,25 +199,25 @@ module ActiveRecord
199
199
  # end
200
200
  #
201
201
  # Entry.access_notice_messages
202
- # entry.access_notice_message
203
- # entry.access_notice_message?
202
+ # @entry.access_notice_message
203
+ # @entry.access_notice_message?
204
204
  #
205
205
  # === Options
206
206
  #
207
207
  # The +options+ are passed directly to the +belongs_to+ call, so this is where you declare +dependent+ etc.
208
208
  # The following options can be included to specialize the behavior of the delegated type convenience methods.
209
209
  #
210
- # [:foreign_key]
210
+ # [+:foreign_key+]
211
211
  # Specify the foreign key used for the convenience methods. By default this is guessed to be the passed
212
212
  # +role+ with an "_id" suffix. So a class that defines a
213
213
  # <tt>delegated_type :entryable, types: %w[ Message Comment ]</tt> association will use "entryable_id" as
214
214
  # the default <tt>:foreign_key</tt>.
215
- # [:foreign_type]
215
+ # [+:foreign_type+]
216
216
  # Specify the column used to store the associated object's type. By default this is inferred to be the passed
217
217
  # +role+ with a "_type" suffix. A class that defines a
218
218
  # <tt>delegated_type :entryable, types: %w[ Message Comment ]</tt> association will use "entryable_type" as
219
219
  # the default <tt>:foreign_type</tt>.
220
- # [:primary_key]
220
+ # [+:primary_key+]
221
221
  # Specify the method that returns the primary key of associated object used for the convenience methods.
222
222
  # By default this is +id+.
223
223
  #
@@ -226,8 +226,8 @@ module ActiveRecord
226
226
  # delegated_type :entryable, types: %w[ Message Comment ], primary_key: :uuid, foreign_key: :entryable_uuid
227
227
  # end
228
228
  #
229
- # Entry#message_uuid # => returns entryable_uuid, when entryable_type == "Message", otherwise nil
230
- # Entry#comment_uuid # => returns entryable_uuid, when entryable_type == "Comment", otherwise nil
229
+ # @entry.message_uuid # => returns entryable_uuid, when entryable_type == "Message", otherwise nil
230
+ # @entry.comment_uuid # => returns entryable_uuid, when entryable_type == "Comment", otherwise nil
231
231
  def delegated_type(role, types:, **options)
232
232
  belongs_to role, options.delete(:scope), **options.merge(polymorphic: true)
233
233
  define_delegated_type_methods role, types: types, options: options
@@ -108,9 +108,9 @@ module ActiveRecord
108
108
  begin
109
109
  if pending?
110
110
  @event_buffer = EventBuffer.new(self, @instrumenter)
111
- connection.with_instrumenter(@event_buffer) do
112
- execute_query(connection, async: true)
113
- end
111
+ ActiveSupport::IsolatedExecutionState[:active_record_instrumenter] = @event_buffer
112
+
113
+ execute_query(connection, async: true)
114
114
  end
115
115
  ensure
116
116
  @mutex.unlock
@@ -9,7 +9,7 @@ module ActiveRecord
9
9
  module VERSION
10
10
  MAJOR = 8
11
11
  MINOR = 0
12
- TINY = 1
12
+ TINY = 2
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -213,7 +213,9 @@ module ActiveRecord
213
213
  raise ActiveRecord::IrreversibleMigration, "To avoid mistakes, drop_table is only reversible if given options or a block (can be empty)."
214
214
  end
215
215
 
216
- super(args.push(options), &block)
216
+ args << options unless options.empty?
217
+
218
+ super(args, &block)
217
219
  end
218
220
 
219
221
  def invert_rename_table(args)
@@ -380,7 +382,8 @@ module ActiveRecord
380
382
  raise ActiveRecord::IrreversibleMigration, "rename_enum_value is only reversible if given a :from and :to option."
381
383
  end
382
384
 
383
- [:rename_enum_value, [type_name, from: options[:to], to: options[:from]]]
385
+ options[:to], options[:from] = options[:from], options[:to]
386
+ [:rename_enum_value, [type_name, options]]
384
387
  end
385
388
 
386
389
  def invert_drop_virtual_table(args)
@@ -160,7 +160,7 @@ db_namespace = namespace :db do
160
160
  end
161
161
  end
162
162
 
163
- # desc 'Resets your database using your migrations for the current environment'
163
+ desc "Resets your database using your migrations for the current environment"
164
164
  task reset: ["db:drop", "db:create", "db:schema:dump", "db:migrate"]
165
165
 
166
166
  desc 'Run the "up" for a given migration VERSION.'
@@ -410,6 +410,18 @@ module ActiveRecord
410
410
  async.ids
411
411
  end
412
412
 
413
+ protected
414
+ def aggregate_column(column_name)
415
+ case column_name
416
+ when Arel::Expressions
417
+ column_name
418
+ when :all
419
+ Arel.star
420
+ else
421
+ arel_column(column_name)
422
+ end
423
+ end
424
+
413
425
  private
414
426
  def all_attributes?(column_names)
415
427
  (column_names.map(&:to_s) - model.attribute_names - model.attribute_aliases.keys).empty?
@@ -450,17 +462,6 @@ module ActiveRecord
450
462
  column_name.is_a?(::String) && /\bDISTINCT[\s(]/i.match?(column_name)
451
463
  end
452
464
 
453
- def aggregate_column(column_name)
454
- case column_name
455
- when Arel::Expressions
456
- column_name
457
- when :all
458
- Arel.star
459
- else
460
- arel_column(column_name)
461
- end
462
- end
463
-
464
465
  def operation_over_aggregate_column(column, operation, distinct)
465
466
  operation == "count" ? column.count(distinct) : column.public_send(operation)
466
467
  end
@@ -476,7 +477,7 @@ module ActiveRecord
476
477
  # PostgreSQL doesn't like ORDER BY when there are no GROUP BY
477
478
  relation = unscope(:order).distinct!(false)
478
479
 
479
- column = aggregate_column(column_name)
480
+ column = relation.aggregate_column(column_name)
480
481
  select_value = operation_over_aggregate_column(column, operation, distinct)
481
482
  select_value.distinct = true if operation == "sum" && distinct
482
483
 
@@ -486,7 +487,11 @@ module ActiveRecord
486
487
  end
487
488
 
488
489
  query_result = if relation.where_clause.contradiction?
489
- ActiveRecord::Result.empty
490
+ if @async
491
+ FutureResult.wrap(ActiveRecord::Result.empty)
492
+ else
493
+ ActiveRecord::Result.empty
494
+ end
490
495
  else
491
496
  skip_query_cache_if_necessary do
492
497
  model.with_connection do |c|
@@ -515,7 +520,9 @@ module ActiveRecord
515
520
  associated = association && association.belongs_to? # only count belongs_to associations
516
521
  group_fields = Array(association.foreign_key) if associated
517
522
  end
518
- group_fields = arel_columns(group_fields)
523
+
524
+ relation = except(:group).distinct!(false)
525
+ group_fields = relation.arel_columns(group_fields)
519
526
 
520
527
  model.with_connection do |connection|
521
528
  column_alias_tracker = ColumnAliasTracker.new(connection)
@@ -526,7 +533,7 @@ module ActiveRecord
526
533
  }
527
534
  group_columns = group_aliases.zip(group_fields)
528
535
 
529
- column = aggregate_column(column_name)
536
+ column = relation.aggregate_column(column_name)
530
537
  column_alias = column_alias_tracker.alias_for("#{operation} #{column_name.to_s.downcase}")
531
538
  select_value = operation_over_aggregate_column(column, operation, distinct)
532
539
  select_value.as(model.adapter_class.quote_column_name(column_alias))
@@ -543,7 +550,6 @@ module ActiveRecord
543
550
  end
544
551
  }
545
552
 
546
- relation = except(:group).distinct!(false)
547
553
  relation.group_values = group_fields
548
554
  relation.select_values = select_values
549
555
 
@@ -659,7 +665,7 @@ module ActiveRecord
659
665
  relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
660
666
  else
661
667
  column_alias = Arel.sql("count_column")
662
- relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
668
+ relation.select_values = [ relation.aggregate_column(column_name).as(column_alias) ]
663
669
  end
664
670
 
665
671
  subquery_alias = Arel.sql("subquery_for_count", retryable: true)
@@ -820,7 +820,7 @@ module ActiveRecord
820
820
  #
821
821
  # [:returning]
822
822
  # (PostgreSQL, SQLite3, and MariaDB only) An array of attributes to return for all successfully
823
- # inserted records, which by default is the primary key.
823
+ # upserted records, which by default is the primary key.
824
824
  # Pass <tt>returning: %w[ id name ]</tt> for both id and name
825
825
  # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
826
826
  # clause entirely.
@@ -76,8 +76,9 @@ module ActiveRecord
76
76
  end
77
77
 
78
78
  # The verifier instance that all signed ids are generated and verified from. By default, it'll be initialized
79
- # with the class-level +signed_id_verifier_secret+, which within \Rails comes from the
80
- # Rails.application.key_generator. By default, it's SHA256 for the digest and JSON for the serialization.
79
+ # with the class-level +signed_id_verifier_secret+, which within Rails comes from
80
+ # {Rails.application.key_generator}[rdoc-ref:Rails::Application#key_generator].
81
+ # By default, it's SHA256 for the digest and JSON for the serialization.
81
82
  def signed_id_verifier
82
83
  @signed_id_verifier ||= begin
83
84
  secret = signed_id_verifier_secret
@@ -93,7 +94,7 @@ module ActiveRecord
93
94
 
94
95
  # Allows you to pass in a custom verifier used for the signed ids. This also allows you to use different
95
96
  # verifiers for different classes. This is also helpful if you need to rotate keys, as you can prepare
96
- # your custom verifier for that in advance. See +ActiveSupport::MessageVerifier+ for details.
97
+ # your custom verifier for that in advance. See ActiveSupport::MessageVerifier for details.
97
98
  def signed_id_verifier=(verifier)
98
99
  @signed_id_verifier = verifier
99
100
  end
@@ -74,13 +74,13 @@ module ActiveRecord
74
74
  self
75
75
  end
76
76
 
77
- def add_bind(obj)
77
+ def add_bind(obj, &)
78
78
  @binds << obj
79
79
  @parts << Substitute.new
80
80
  self
81
81
  end
82
82
 
83
- def add_binds(binds, proc_for_binds = nil)
83
+ def add_binds(binds, proc_for_binds = nil, &)
84
84
  @binds.concat proc_for_binds ? binds.map(&proc_for_binds) : binds
85
85
  binds.size.times do |i|
86
86
  @parts << ", " unless i == 0
@@ -219,12 +219,11 @@ module ActiveRecord
219
219
  # database error will occur because the savepoint has already been
220
220
  # automatically released. The following example demonstrates the problem:
221
221
  #
222
- # Model.lease_connection.transaction do # BEGIN
223
- # Model.lease_connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
224
- # Model.lease_connection.create_table(...) # active_record_1 now automatically released
225
- # end # RELEASE SAVEPOINT active_record_1
226
- # # ^^^^ BOOM! database error!
227
- # end
222
+ # Model.transaction do # BEGIN
223
+ # Model.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
224
+ # Model.lease_connection.create_table(...) # active_record_1 now automatically released
225
+ # end # RELEASE SAVEPOINT active_record_1
226
+ # end # ^^^^ BOOM! database error!
228
227
  #
229
228
  # Note that "TRUNCATE" is also a MySQL DDL statement!
230
229
  module ClassMethods
@@ -18,7 +18,7 @@ module Arel # :nodoc: all
18
18
  self
19
19
  end
20
20
 
21
- def add_binds(binds, proc_for_binds = nil)
21
+ def add_binds(binds, proc_for_binds = nil, &)
22
22
  @binds.concat proc_for_binds ? binds.map(&proc_for_binds) : binds
23
23
  self
24
24
  end
@@ -12,7 +12,7 @@ module Arel # :nodoc: all
12
12
  @bind_index = 1
13
13
  end
14
14
 
15
- def add_bind(bind)
15
+ def add_bind(bind, &)
16
16
  self << yield(@bind_index)
17
17
  @bind_index += 1
18
18
  self
@@ -15,12 +15,12 @@ module Arel # :nodoc: all
15
15
  self
16
16
  end
17
17
 
18
- def add_bind(bind)
18
+ def add_bind(bind, &)
19
19
  bind = bind.value_for_database if bind.respond_to?(:value_for_database)
20
20
  self << quoter.quote(bind)
21
21
  end
22
22
 
23
- def add_binds(binds, proc_for_binds = nil)
23
+ def add_binds(binds, proc_for_binds = nil, &)
24
24
  self << binds.map { |bind| quoter.quote(bind) }.join(", ")
25
25
  end
26
26
 
@@ -30,7 +30,7 @@ module Arel # :nodoc: all
30
30
  end
31
31
 
32
32
  module FetchAttribute
33
- def fetch_attribute
33
+ def fetch_attribute(&)
34
34
  if left.is_a?(Arel::Attributes::Attribute)
35
35
  yield left
36
36
  elsif right.is_a?(Arel::Attributes::Attribute)
@@ -152,7 +152,7 @@ module Arel # :nodoc: all
152
152
  end
153
153
  end
154
154
 
155
- def fetch_attribute
155
+ def fetch_attribute(&)
156
156
  end
157
157
 
158
158
  def equality?; false; end
@@ -19,7 +19,7 @@ module Arel # :nodoc: all
19
19
  coder.scalar = self.to_s
20
20
  end
21
21
 
22
- def fetch_attribute
22
+ def fetch_attribute(&)
23
23
  end
24
24
 
25
25
  def +(other)
@@ -763,7 +763,7 @@ module Arel # :nodoc: all
763
763
 
764
764
  def visit_Arel_Nodes_SqlLiteral(o, collector)
765
765
  collector.preparable = false
766
- collector.retryable = o.retryable
766
+ collector.retryable &&= o.retryable
767
767
  collector << o.to_s
768
768
  end
769
769