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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +138 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/attributes.rb +2 -2
- data/lib/active_record/autosave_association.rb +21 -11
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +17 -14
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +14 -9
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +39 -22
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +4 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -1
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +12 -12
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +7 -2
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +6 -1
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -1
- data/lib/active_record/core.rb +31 -2
- data/lib/active_record/counter_cache.rb +1 -1
- data/lib/active_record/delegated_type.rb +17 -17
- data/lib/active_record/future_result.rb +3 -3
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +5 -2
- data/lib/active_record/railties/databases.rake +1 -1
- data/lib/active_record/relation/calculations.rb +23 -17
- data/lib/active_record/relation.rb +1 -1
- data/lib/active_record/signed_id.rb +4 -3
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/transactions.rb +5 -6
- data/lib/arel/collectors/bind.rb +1 -1
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +2 -2
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/node.rb +1 -1
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/visitors/to_sql.rb +1 -1
- 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
|
-
|
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
|
45
|
-
|
46
|
-
|
43
|
+
def connection_descriptor=(connection_descriptor)
|
44
|
+
case connection_descriptor
|
45
|
+
when ConnectionHandler::ConnectionDescriptor
|
46
|
+
@connection_descriptor = connection_descriptor
|
47
47
|
else
|
48
|
-
|
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(
|
312
|
-
@base.add_exclusion_constraint(name,
|
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(
|
321
|
-
@base.remove_exclusion_constraint(name,
|
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(
|
330
|
-
@base.add_unique_constraint(name,
|
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(
|
339
|
-
@base.remove_unique_constraint(name,
|
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(
|
349
|
-
@base.validate_constraint(name,
|
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(
|
359
|
-
@base.validate_check_constraint(name,
|
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.
|
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
|
-
|
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
|
data/lib/active_record/core.rb
CHANGED
@@ -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
|
-
#
|
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.
|
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
|
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
|
-
#
|
185
|
-
#
|
186
|
-
# Entry.messages
|
187
|
-
#
|
188
|
-
#
|
189
|
-
#
|
190
|
-
# Entry.comments
|
191
|
-
#
|
192
|
-
#
|
193
|
-
#
|
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
|
-
# [
|
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
|
-
# [
|
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
|
-
# [
|
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
|
-
#
|
230
|
-
#
|
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
|
-
|
112
|
-
|
113
|
-
|
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
|
@@ -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
|
-
|
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
|
-
[:
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
#
|
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
|
80
|
-
# Rails.application.key_generator.
|
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
|
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.
|
223
|
-
# Model.
|
224
|
-
# Model.lease_connection.create_table(...)
|
225
|
-
# end
|
226
|
-
#
|
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
|
data/lib/arel/collectors/bind.rb
CHANGED
@@ -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
|
|
data/lib/arel/nodes/binary.rb
CHANGED
data/lib/arel/nodes/node.rb
CHANGED
data/lib/arel/visitors/to_sql.rb
CHANGED