activerecord 7.1.5.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 +369 -2484
- data/README.rdoc +15 -15
- data/examples/performance.rb +2 -2
- data/lib/active_record/association_relation.rb +2 -1
- data/lib/active_record/associations/alias_tracker.rb +31 -23
- data/lib/active_record/associations/association.rb +43 -12
- data/lib/active_record/associations/belongs_to_association.rb +21 -8
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +3 -2
- data/lib/active_record/associations/builder/association.rb +7 -6
- data/lib/active_record/associations/builder/belongs_to.rb +1 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +3 -4
- data/lib/active_record/associations/builder/has_one.rb +3 -4
- data/lib/active_record/associations/collection_association.rb +17 -9
- data/lib/active_record/associations/collection_proxy.rb +14 -1
- data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +10 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +4 -3
- data/lib/active_record/associations/preloader/branch.rb +7 -1
- data/lib/active_record/associations/preloader/through_association.rb +1 -3
- data/lib/active_record/associations/singular_association.rb +14 -3
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +92 -295
- data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/primary_key.rb +25 -61
- data/lib/active_record/attribute_methods/read.rb +1 -13
- data/lib/active_record/attribute_methods/serialization.rb +4 -24
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -18
- data/lib/active_record/attribute_methods.rb +71 -75
- data/lib/active_record/attributes.rb +63 -49
- data/lib/active_record/autosave_association.rb +92 -57
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +48 -122
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +286 -77
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +119 -55
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +197 -76
- data/lib/active_record/connection_adapters/abstract/quoting.rb +66 -92
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -12
- data/lib/active_record/connection_adapters/abstract/transaction.rb +140 -67
- data/lib/active_record/connection_adapters/abstract_adapter.rb +85 -90
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +71 -52
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +9 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -57
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +56 -45
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +92 -101
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +13 -31
- data/lib/active_record/connection_adapters/pool_config.rb +14 -13
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -41
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +58 -58
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -4
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +1 -11
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +36 -20
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +75 -28
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +73 -113
- data/lib/active_record/connection_adapters/schema_cache.rb +124 -131
- data/lib/active_record/connection_adapters/sqlite3/column.rb +14 -1
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +81 -97
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +57 -46
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +29 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +35 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +183 -87
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +39 -69
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +19 -65
- data/lib/active_record/connection_adapters.rb +65 -0
- data/lib/active_record/connection_handling.rb +74 -37
- data/lib/active_record/core.rb +132 -51
- data/lib/active_record/counter_cache.rb +19 -10
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -2
- data/lib/active_record/database_configurations/database_config.rb +23 -4
- data/lib/active_record/database_configurations/hash_config.rb +46 -34
- data/lib/active_record/database_configurations/url_config.rb +20 -1
- data/lib/active_record/database_configurations.rb +1 -1
- data/lib/active_record/delegated_type.rb +41 -17
- data/lib/active_record/dynamic_matchers.rb +2 -2
- data/lib/active_record/encryption/config.rb +3 -1
- data/lib/active_record/encryption/encryptable_record.rb +7 -7
- data/lib/active_record/encryption/encrypted_attribute_type.rb +33 -4
- data/lib/active_record/encryption/encryptor.rb +28 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
- data/lib/active_record/encryption/key_provider.rb +1 -1
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +4 -0
- data/lib/active_record/encryption/null_encryptor.rb +4 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +4 -0
- data/lib/active_record/encryption/scheme.rb +8 -1
- data/lib/active_record/enum.rb +20 -16
- data/lib/active_record/errors.rb +54 -20
- data/lib/active_record/explain.rb +13 -24
- data/lib/active_record/fixtures.rb +37 -33
- data/lib/active_record/future_result.rb +21 -13
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +4 -2
- data/lib/active_record/insert_all.rb +19 -16
- data/lib/active_record/integration.rb +4 -1
- data/lib/active_record/internal_metadata.rb +48 -34
- data/lib/active_record/locking/optimistic.rb +8 -7
- data/lib/active_record/log_subscriber.rb +5 -32
- data/lib/active_record/message_pack.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +33 -14
- data/lib/active_record/migration/compatibility.rb +8 -3
- data/lib/active_record/migration/default_strategy.rb +4 -5
- data/lib/active_record/migration/pending_migration_connection.rb +2 -2
- data/lib/active_record/migration.rb +104 -98
- data/lib/active_record/model_schema.rb +32 -70
- data/lib/active_record/nested_attributes.rb +15 -9
- data/lib/active_record/normalization.rb +3 -7
- data/lib/active_record/persistence.rb +127 -451
- data/lib/active_record/query_cache.rb +19 -8
- data/lib/active_record/query_logs.rb +104 -37
- data/lib/active_record/query_logs_formatter.rb +17 -28
- data/lib/active_record/querying.rb +24 -12
- data/lib/active_record/railtie.rb +26 -68
- data/lib/active_record/railties/controller_runtime.rb +13 -4
- data/lib/active_record/railties/databases.rake +43 -61
- data/lib/active_record/reflection.rb +112 -53
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +138 -72
- data/lib/active_record/relation/calculations.rb +122 -82
- data/lib/active_record/relation/delegation.rb +30 -22
- data/lib/active_record/relation/finder_methods.rb +32 -18
- data/lib/active_record/relation/merger.rb +12 -14
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +10 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
- data/lib/active_record/relation/predicate_builder.rb +16 -3
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +317 -101
- data/lib/active_record/relation/spawn_methods.rb +3 -19
- data/lib/active_record/relation/where_clause.rb +7 -19
- data/lib/active_record/relation.rb +561 -119
- data/lib/active_record/result.rb +95 -46
- data/lib/active_record/runtime_registry.rb +39 -0
- data/lib/active_record/sanitization.rb +31 -25
- data/lib/active_record/schema.rb +8 -6
- data/lib/active_record/schema_dumper.rb +53 -20
- data/lib/active_record/schema_migration.rb +31 -14
- data/lib/active_record/scoping/named.rb +6 -2
- data/lib/active_record/signed_id.rb +24 -4
- data/lib/active_record/statement_cache.rb +19 -19
- data/lib/active_record/store.rb +7 -3
- data/lib/active_record/table_metadata.rb +2 -13
- data/lib/active_record/tasks/database_tasks.rb +87 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -3
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +4 -3
- data/lib/active_record/test_fixtures.rb +98 -89
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/token_for.rb +22 -12
- data/lib/active_record/touch_later.rb +1 -1
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +72 -17
- data/lib/active_record/translation.rb +0 -2
- data/lib/active_record/type/serialized.rb +1 -3
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/associated.rb +9 -3
- data/lib/active_record/validations/uniqueness.rb +23 -18
- data/lib/active_record/validations.rb +4 -1
- data/lib/active_record.rb +138 -57
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/collectors/bind.rb +4 -2
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +2 -2
- data/lib/arel/collectors/substitute_binds.rb +3 -3
- data/lib/arel/nodes/binary.rb +1 -7
- data/lib/arel/nodes/bound_sql_literal.rb +9 -5
- data/lib/arel/nodes/{and.rb → nary.rb} +5 -2
- data/lib/arel/nodes/node.rb +5 -4
- data/lib/arel/nodes/sql_literal.rb +8 -1
- data/lib/arel/nodes.rb +2 -2
- data/lib/arel/predications.rb +1 -1
- data/lib/arel/select_manager.rb +1 -1
- data/lib/arel/table.rb +3 -7
- data/lib/arel/tree_manager.rb +3 -2
- data/lib/arel/update_manager.rb +2 -1
- data/lib/arel/visitors/dot.rb +1 -0
- data/lib/arel/visitors/mysql.rb +9 -4
- data/lib/arel/visitors/postgresql.rb +1 -12
- data/lib/arel/visitors/sqlite.rb +25 -0
- data/lib/arel/visitors/to_sql.rb +29 -16
- data/lib/arel.rb +7 -3
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- metadata +18 -16
- data/lib/active_record/relation/record_fetch_warning.rb +0 -49
@@ -188,6 +188,27 @@ module ActiveRecord
|
|
188
188
|
# #after_commit is a good spot to put in a hook to clearing a cache since clearing it from
|
189
189
|
# within a transaction could trigger the cache to be regenerated before the database is updated.
|
190
190
|
#
|
191
|
+
# ==== NOTE: Callbacks are deduplicated per callback by filter.
|
192
|
+
#
|
193
|
+
# Trying to define multiple callbacks with the same filter will result in a single callback being run.
|
194
|
+
#
|
195
|
+
# For example:
|
196
|
+
#
|
197
|
+
# after_commit :do_something
|
198
|
+
# after_commit :do_something # only the last one will be called
|
199
|
+
#
|
200
|
+
# This applies to all variations of <tt>after_*_commit</tt> callbacks as well.
|
201
|
+
#
|
202
|
+
# after_commit :do_something
|
203
|
+
# after_create_commit :do_something
|
204
|
+
# after_save_commit :do_something
|
205
|
+
#
|
206
|
+
# It is recommended to use the +on:+ option to specify when the callback should be run.
|
207
|
+
#
|
208
|
+
# after_commit :do_something, on: [:create, :update]
|
209
|
+
#
|
210
|
+
# This is equivalent to using +after_create_commit+ and +after_update_commit+, but will not be deduplicated.
|
211
|
+
#
|
191
212
|
# === Caveats
|
192
213
|
#
|
193
214
|
# If you're on MySQL, then do not use Data Definition Language (DDL) operations in nested
|
@@ -198,18 +219,30 @@ module ActiveRecord
|
|
198
219
|
# database error will occur because the savepoint has already been
|
199
220
|
# automatically released. The following example demonstrates the problem:
|
200
221
|
#
|
201
|
-
# Model.
|
202
|
-
# Model.
|
203
|
-
# Model.
|
204
|
-
# end
|
205
|
-
#
|
206
|
-
# 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!
|
207
227
|
#
|
208
228
|
# Note that "TRUNCATE" is also a MySQL DDL statement!
|
209
229
|
module ClassMethods
|
210
230
|
# See the ConnectionAdapters::DatabaseStatements#transaction API docs.
|
211
231
|
def transaction(**options, &block)
|
212
|
-
connection
|
232
|
+
with_connection do |connection|
|
233
|
+
connection.transaction(**options, &block)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# Returns a representation of the current transaction state,
|
238
|
+
# which can be a top level transaction, a savepoint, or the absence of a transaction.
|
239
|
+
#
|
240
|
+
# An object is always returned, whether or not a transaction is currently active.
|
241
|
+
# To check if a transaction was opened, use <tt>current_transaction.open?</tt>.
|
242
|
+
#
|
243
|
+
# See the ActiveRecord::Transaction documentation for detailed behavior.
|
244
|
+
def current_transaction
|
245
|
+
connection_pool.active_connection&.current_transaction&.user_transaction || Transaction::NULL_TRANSACTION
|
213
246
|
end
|
214
247
|
|
215
248
|
def before_commit(*args, &block) # :nodoc:
|
@@ -266,6 +299,25 @@ module ActiveRecord
|
|
266
299
|
set_callback(:rollback, :after, *args, &block)
|
267
300
|
end
|
268
301
|
|
302
|
+
# Similar to ActiveSupport::Callbacks::ClassMethods#set_callback, but with
|
303
|
+
# support for options available on #after_commit and #after_rollback callbacks.
|
304
|
+
def set_callback(name, *filter_list, &block)
|
305
|
+
options = filter_list.extract_options!
|
306
|
+
filter_list << options
|
307
|
+
|
308
|
+
if name.in?([:commit, :rollback]) && options[:on]
|
309
|
+
fire_on = Array(options[:on])
|
310
|
+
assert_valid_transaction_action(fire_on)
|
311
|
+
options[:if] = [
|
312
|
+
-> { transaction_include_any_action?(fire_on) },
|
313
|
+
*options[:if]
|
314
|
+
]
|
315
|
+
end
|
316
|
+
|
317
|
+
|
318
|
+
super(name, *filter_list, &block)
|
319
|
+
end
|
320
|
+
|
269
321
|
private
|
270
322
|
def prepend_option
|
271
323
|
if ActiveRecord.run_after_transaction_callbacks_in_order_defined
|
@@ -354,18 +406,19 @@ module ActiveRecord
|
|
354
406
|
# This method is available within the context of an ActiveRecord::Base
|
355
407
|
# instance.
|
356
408
|
def with_transaction_returning_status
|
357
|
-
|
358
|
-
|
359
|
-
|
409
|
+
self.class.with_connection do |connection|
|
410
|
+
status = nil
|
411
|
+
ensure_finalize = !connection.transaction_open?
|
360
412
|
|
361
|
-
|
362
|
-
|
363
|
-
|
413
|
+
connection.transaction do
|
414
|
+
add_to_transaction(ensure_finalize || has_transactional_callbacks?)
|
415
|
+
remember_transaction_record_state
|
364
416
|
|
365
|
-
|
366
|
-
|
417
|
+
status = yield
|
418
|
+
raise ActiveRecord::Rollback unless status
|
419
|
+
end
|
420
|
+
status
|
367
421
|
end
|
368
|
-
status
|
369
422
|
end
|
370
423
|
|
371
424
|
def trigger_transactional_callbacks? # :nodoc:
|
@@ -457,7 +510,9 @@ module ActiveRecord
|
|
457
510
|
# Add the record to the current transaction so that the #after_rollback and #after_commit
|
458
511
|
# callbacks can be called.
|
459
512
|
def add_to_transaction(ensure_finalize = true)
|
460
|
-
self.class.connection
|
513
|
+
self.class.with_connection do |connection|
|
514
|
+
connection.add_transaction_record(self, ensure_finalize)
|
515
|
+
end
|
461
516
|
end
|
462
517
|
|
463
518
|
def has_transactional_callbacks?
|
@@ -14,18 +14,18 @@ module ActiveRecord
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def type_for_attribute(attr_name)
|
17
|
-
schema_cache =
|
17
|
+
schema_cache = @klass.schema_cache
|
18
18
|
|
19
19
|
if schema_cache.data_source_exists?(table_name)
|
20
20
|
column = schema_cache.columns_hash(table_name)[attr_name.to_s]
|
21
|
-
|
21
|
+
if column
|
22
|
+
type = @klass.with_connection { |connection| connection.lookup_cast_type_from_column(column) }
|
23
|
+
end
|
22
24
|
end
|
23
25
|
|
24
26
|
type || Type.default_value
|
25
27
|
end
|
26
28
|
|
27
|
-
delegate :connection, to: :@klass, private: true
|
28
|
-
|
29
29
|
private
|
30
30
|
attr_reader :table_name
|
31
31
|
end
|
@@ -4,14 +4,20 @@ module ActiveRecord
|
|
4
4
|
module Validations
|
5
5
|
class AssociatedValidator < ActiveModel::EachValidator # :nodoc:
|
6
6
|
def validate_each(record, attribute, value)
|
7
|
-
|
7
|
+
context = record_validation_context_for_association(record)
|
8
|
+
|
9
|
+
if Array(value).reject { |association| valid_object?(association, context) }.any?
|
8
10
|
record.errors.add(attribute, :invalid, **options.merge(value: value))
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
12
14
|
private
|
13
|
-
def valid_object?(record)
|
14
|
-
(record.respond_to?(:marked_for_destruction?) && record.marked_for_destruction?) || record.valid?
|
15
|
+
def valid_object?(record, context)
|
16
|
+
(record.respond_to?(:marked_for_destruction?) && record.marked_for_destruction?) || record.valid?(context)
|
17
|
+
end
|
18
|
+
|
19
|
+
def record_validation_context_for_association(record)
|
20
|
+
record.custom_validation_context? ? record.validation_context : nil
|
15
21
|
end
|
16
22
|
end
|
17
23
|
|
@@ -14,6 +14,7 @@ module ActiveRecord
|
|
14
14
|
end
|
15
15
|
super
|
16
16
|
@klass = options[:class]
|
17
|
+
@klass = @klass.superclass if @klass.singleton_class?
|
17
18
|
end
|
18
19
|
|
19
20
|
def validate_each(record, attribute, value)
|
@@ -53,17 +54,17 @@ module ActiveRecord
|
|
53
54
|
private
|
54
55
|
# The check for an existing value should be run from a class that
|
55
56
|
# isn't abstract. This means working down from the current class
|
56
|
-
# (self), to the first non-abstract class.
|
57
|
-
# their subclasses, we have to build the hierarchy between self and
|
58
|
-
# the record's class.
|
57
|
+
# (self), to the first non-abstract class.
|
59
58
|
def find_finder_class_for(record)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
59
|
+
current_class = record.class
|
60
|
+
found_class = nil
|
61
|
+
loop do
|
62
|
+
found_class = current_class unless current_class.abstract_class?
|
63
|
+
break if current_class == @klass
|
64
|
+
current_class = current_class.superclass
|
64
65
|
end
|
65
66
|
|
66
|
-
|
67
|
+
found_class
|
67
68
|
end
|
68
69
|
|
69
70
|
def validation_needed?(klass, record, attribute)
|
@@ -84,7 +85,7 @@ module ActiveRecord
|
|
84
85
|
attributes = scope + [attr]
|
85
86
|
attributes = resolve_attributes(record, attributes)
|
86
87
|
|
87
|
-
klass.
|
88
|
+
klass.schema_cache.indexes(klass.table_name).any? do |index|
|
88
89
|
index.unique &&
|
89
90
|
index.where.nil? &&
|
90
91
|
(Array(index.columns) - attributes).empty?
|
@@ -110,16 +111,20 @@ module ActiveRecord
|
|
110
111
|
|
111
112
|
def build_relation(klass, attribute, value)
|
112
113
|
relation = klass.unscoped
|
113
|
-
|
114
|
-
|
114
|
+
# TODO: Add case-sensitive / case-insensitive operators to Arel
|
115
|
+
# to no longer need to checkout a connection here.
|
116
|
+
comparison = klass.with_connection do |connection|
|
117
|
+
relation.bind_attribute(attribute, value) do |attr, bind|
|
118
|
+
return relation.none! if bind.unboundable?
|
115
119
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
120
|
+
if !options.key?(:case_sensitive) || bind.nil?
|
121
|
+
connection.default_uniqueness_comparison(attr, bind)
|
122
|
+
elsif options[:case_sensitive]
|
123
|
+
connection.case_sensitive_comparison(attr, bind)
|
124
|
+
else
|
125
|
+
# will use SQL LOWER function before comparison, unless it detects a case insensitive collation
|
126
|
+
connection.case_insensitive_comparison(attr, bind)
|
127
|
+
end
|
123
128
|
end
|
124
129
|
end
|
125
130
|
|
@@ -39,7 +39,6 @@ module ActiveRecord
|
|
39
39
|
# {new_record?}[rdoc-ref:Persistence#new_record?].
|
40
40
|
module Validations
|
41
41
|
extend ActiveSupport::Concern
|
42
|
-
include ActiveModel::Validations
|
43
42
|
|
44
43
|
# The validation process on save can be skipped by passing <tt>validate: false</tt>.
|
45
44
|
# The validation context can be changed by passing <tt>context: context</tt>.
|
@@ -75,6 +74,10 @@ module ActiveRecord
|
|
75
74
|
|
76
75
|
alias_method :validate, :valid?
|
77
76
|
|
77
|
+
def custom_validation_context? # :nodoc:
|
78
|
+
validation_context && [:create, :update].exclude?(validation_context)
|
79
|
+
end
|
80
|
+
|
78
81
|
private
|
79
82
|
def default_validation_context
|
80
83
|
new_record? ? :create : :update
|
data/lib/active_record.rb
CHANGED
@@ -25,9 +25,11 @@
|
|
25
25
|
|
26
26
|
require "active_support"
|
27
27
|
require "active_support/rails"
|
28
|
+
require "active_support/ordered_options"
|
28
29
|
require "active_model"
|
29
30
|
require "arel"
|
30
31
|
require "yaml"
|
32
|
+
require "zlib"
|
31
33
|
|
32
34
|
require "active_record/version"
|
33
35
|
require "active_record/deprecator"
|
@@ -85,6 +87,7 @@ module ActiveRecord
|
|
85
87
|
autoload :Timestamp
|
86
88
|
autoload :TokenFor
|
87
89
|
autoload :TouchLater
|
90
|
+
autoload :Transaction
|
88
91
|
autoload :Transactions
|
89
92
|
autoload :Translation
|
90
93
|
autoload :Validations
|
@@ -128,6 +131,8 @@ module ActiveRecord
|
|
128
131
|
module AttributeMethods
|
129
132
|
extend ActiveSupport::Autoload
|
130
133
|
|
134
|
+
autoload :CompositePrimaryKey
|
135
|
+
|
131
136
|
eager_autoload do
|
132
137
|
autoload :BeforeTypeCast
|
133
138
|
autoload :Dirty
|
@@ -177,18 +182,35 @@ module ActiveRecord
|
|
177
182
|
singleton_class.attr_accessor :disable_prepared_statements
|
178
183
|
self.disable_prepared_statements = false
|
179
184
|
|
185
|
+
##
|
186
|
+
# :singleton-method: lazily_load_schema_cache
|
180
187
|
# Lazily load the schema cache. This option will load the schema cache
|
181
|
-
# when a connection is established rather than on boot.
|
182
|
-
# +config.active_record.use_schema_cache_dump+ will be set to false.
|
188
|
+
# when a connection is established rather than on boot.
|
183
189
|
singleton_class.attr_accessor :lazily_load_schema_cache
|
184
190
|
self.lazily_load_schema_cache = false
|
185
191
|
|
192
|
+
##
|
193
|
+
# :singleton-method: schema_cache_ignored_tables
|
186
194
|
# A list of tables or regex's to match tables to ignore when
|
187
195
|
# dumping the schema cache. For example if this is set to +[/^_/]+
|
188
196
|
# the schema cache will not dump tables named with an underscore.
|
189
197
|
singleton_class.attr_accessor :schema_cache_ignored_tables
|
190
198
|
self.schema_cache_ignored_tables = []
|
191
199
|
|
200
|
+
# Checks to see if the +table_name+ is ignored by checking
|
201
|
+
# against the +schema_cache_ignored_tables+ option.
|
202
|
+
#
|
203
|
+
# ActiveRecord.schema_cache_ignored_table?(:developers)
|
204
|
+
#
|
205
|
+
def self.schema_cache_ignored_table?(table_name)
|
206
|
+
ActiveRecord.schema_cache_ignored_tables.any? do |ignored|
|
207
|
+
ignored === table_name
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
singleton_class.attr_accessor :database_cli
|
212
|
+
self.database_cli = { postgresql: "psql", mysql: %w[mysql mysql5], sqlite: "sqlite3" }
|
213
|
+
|
192
214
|
singleton_class.attr_reader :default_timezone
|
193
215
|
|
194
216
|
# Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
|
@@ -203,6 +225,8 @@ module ActiveRecord
|
|
203
225
|
|
204
226
|
self.default_timezone = :utc
|
205
227
|
|
228
|
+
##
|
229
|
+
# :singleton-method: db_warnings_action
|
206
230
|
# The action to take when database query produces warning.
|
207
231
|
# Must be one of :ignore, :log, :raise, :report, or a custom proc.
|
208
232
|
# The default is :ignore.
|
@@ -232,6 +256,8 @@ module ActiveRecord
|
|
232
256
|
|
233
257
|
self.db_warnings_action = :ignore
|
234
258
|
|
259
|
+
##
|
260
|
+
# :singleton-method: db_warnings_ignore
|
235
261
|
# Specify allowlist of database warnings.
|
236
262
|
singleton_class.attr_accessor :db_warnings_ignore
|
237
263
|
self.db_warnings_ignore = []
|
@@ -242,14 +268,8 @@ module ActiveRecord
|
|
242
268
|
singleton_class.attr_accessor :reading_role
|
243
269
|
self.reading_role = :reading
|
244
270
|
|
245
|
-
|
246
|
-
|
247
|
-
The `legacy_connection_handling` setter was deprecated in 7.0 and removed in 7.1,
|
248
|
-
but is still defined in your configuration. Please remove this call as it no longer
|
249
|
-
has any effect."
|
250
|
-
MSG
|
251
|
-
end
|
252
|
-
|
271
|
+
##
|
272
|
+
# :singleton-method: async_query_executor
|
253
273
|
# Sets the async_query_executor for an application. By default the thread pool executor
|
254
274
|
# set to +nil+ which will not run queries in the background. Applications must configure
|
255
275
|
# a thread pool executor to use this feature. Options are:
|
@@ -287,11 +307,22 @@ module ActiveRecord
|
|
287
307
|
@global_executor_concurrency ||= nil
|
288
308
|
end
|
289
309
|
|
310
|
+
@permanent_connection_checkout = true
|
311
|
+
singleton_class.attr_reader :permanent_connection_checkout
|
312
|
+
|
313
|
+
# Defines whether +ActiveRecord::Base.connection+ is allowed, deprecated, or entirely disallowed.
|
314
|
+
def self.permanent_connection_checkout=(value)
|
315
|
+
unless [true, :deprecated, :disallowed].include?(value)
|
316
|
+
raise ArgumentError, "permanent_connection_checkout must be one of: `true`, `:deprecated` or `:disallowed`"
|
317
|
+
end
|
318
|
+
@permanent_connection_checkout = value
|
319
|
+
end
|
320
|
+
|
290
321
|
singleton_class.attr_accessor :index_nested_attribute_errors
|
291
322
|
self.index_nested_attribute_errors = false
|
292
323
|
|
293
324
|
##
|
294
|
-
# :singleton-method:
|
325
|
+
# :singleton-method: verbose_query_logs
|
295
326
|
#
|
296
327
|
# Specifies if the methods calling database queries should be logged below
|
297
328
|
# their relevant queries. Defaults to false.
|
@@ -299,7 +330,7 @@ module ActiveRecord
|
|
299
330
|
self.verbose_query_logs = false
|
300
331
|
|
301
332
|
##
|
302
|
-
# :singleton-method:
|
333
|
+
# :singleton-method: queues
|
303
334
|
#
|
304
335
|
# Specifies the names of the queues used by background jobs.
|
305
336
|
singleton_class.attr_accessor :queues
|
@@ -320,30 +351,18 @@ module ActiveRecord
|
|
320
351
|
singleton_class.attr_accessor :run_after_transaction_callbacks_in_order_defined
|
321
352
|
self.run_after_transaction_callbacks_in_order_defined = false
|
322
353
|
|
323
|
-
singleton_class.attr_accessor :commit_transaction_on_non_local_return
|
324
|
-
self.commit_transaction_on_non_local_return = false
|
325
|
-
|
326
|
-
##
|
327
|
-
# :singleton-method:
|
328
|
-
# Specify a threshold for the size of query result sets. If the number of
|
329
|
-
# records in the set exceeds the threshold, a warning is logged. This can
|
330
|
-
# be used to identify queries which load thousands of records and
|
331
|
-
# potentially cause memory bloat.
|
332
|
-
singleton_class.attr_accessor :warn_on_records_fetched_greater_than
|
333
|
-
self.warn_on_records_fetched_greater_than = false
|
334
|
-
|
335
354
|
singleton_class.attr_accessor :application_record_class
|
336
355
|
self.application_record_class = nil
|
337
356
|
|
338
357
|
##
|
339
|
-
# :singleton-method:
|
358
|
+
# :singleton-method: action_on_strict_loading_violation
|
340
359
|
# Set the application to log or raise when an association violates strict loading.
|
341
360
|
# Defaults to :raise.
|
342
361
|
singleton_class.attr_accessor :action_on_strict_loading_violation
|
343
362
|
self.action_on_strict_loading_violation = :raise
|
344
363
|
|
345
364
|
##
|
346
|
-
# :singleton-method:
|
365
|
+
# :singleton-method: schema_format
|
347
366
|
# Specifies the format to use when dumping the database schema with Rails'
|
348
367
|
# Rakefile. If :sql, the schema is dumped as (potentially database-
|
349
368
|
# specific) SQL statements. If :ruby, the schema is dumped as an
|
@@ -354,7 +373,7 @@ module ActiveRecord
|
|
354
373
|
self.schema_format = :ruby
|
355
374
|
|
356
375
|
##
|
357
|
-
# :singleton-method:
|
376
|
+
# :singleton-method: error_on_ignored_order
|
358
377
|
# Specifies if an error should be raised if the query has an order being
|
359
378
|
# ignored when doing batch queries. Useful in applications where the
|
360
379
|
# scope being ignored is error-worthy, rather than a warning.
|
@@ -362,19 +381,27 @@ module ActiveRecord
|
|
362
381
|
self.error_on_ignored_order = false
|
363
382
|
|
364
383
|
##
|
365
|
-
# :singleton-method:
|
384
|
+
# :singleton-method: timestamped_migrations
|
366
385
|
# Specify whether or not to use timestamps for migration versions
|
367
386
|
singleton_class.attr_accessor :timestamped_migrations
|
368
387
|
self.timestamped_migrations = true
|
369
388
|
|
370
389
|
##
|
371
|
-
# :singleton-method:
|
390
|
+
# :singleton-method: validate_migration_timestamps
|
391
|
+
# Specify whether or not to validate migration timestamps. When set, an error
|
392
|
+
# will be raised if a timestamp is more than a day ahead of the timestamp
|
393
|
+
# associated with the current time. +timestamped_migrations+ must be set to true.
|
394
|
+
singleton_class.attr_accessor :validate_migration_timestamps
|
395
|
+
self.validate_migration_timestamps = false
|
396
|
+
|
397
|
+
##
|
398
|
+
# :singleton-method: migration_strategy
|
372
399
|
# Specify strategy to use for executing migrations.
|
373
400
|
singleton_class.attr_accessor :migration_strategy
|
374
401
|
self.migration_strategy = Migration::DefaultStrategy
|
375
402
|
|
376
403
|
##
|
377
|
-
# :singleton-method:
|
404
|
+
# :singleton-method: dump_schema_after_migration
|
378
405
|
# Specify whether schema dump should happen at the end of the
|
379
406
|
# bin/rails db:migrate command. This is true by default, which is useful for the
|
380
407
|
# development environment. This should ideally be false in the production
|
@@ -383,7 +410,7 @@ module ActiveRecord
|
|
383
410
|
self.dump_schema_after_migration = true
|
384
411
|
|
385
412
|
##
|
386
|
-
# :singleton-method:
|
413
|
+
# :singleton-method: dump_schemas
|
387
414
|
# Specifies which database schemas to dump when calling db:schema:dump.
|
388
415
|
# If the value is :schema_search_path (the default), any schemas listed in
|
389
416
|
# schema_search_path are dumped. Use :all to dump all schemas regardless
|
@@ -392,22 +419,8 @@ module ActiveRecord
|
|
392
419
|
singleton_class.attr_accessor :dump_schemas
|
393
420
|
self.dump_schemas = :schema_search_path
|
394
421
|
|
395
|
-
def self.suppress_multiple_database_warning
|
396
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
397
|
-
config.active_record.suppress_multiple_database_warning is deprecated and will be removed in Rails 7.2.
|
398
|
-
It no longer has any effect and should be removed from the configuration file.
|
399
|
-
MSG
|
400
|
-
end
|
401
|
-
|
402
|
-
def self.suppress_multiple_database_warning=(value)
|
403
|
-
ActiveRecord.deprecator.warn(<<-MSG.squish)
|
404
|
-
config.active_record.suppress_multiple_database_warning= is deprecated and will be removed in Rails 7.2.
|
405
|
-
It no longer has any effect and should be removed from the configuration file.
|
406
|
-
MSG
|
407
|
-
end
|
408
|
-
|
409
422
|
##
|
410
|
-
# :singleton-method:
|
423
|
+
# :singleton-method: verify_foreign_keys_for_fixtures
|
411
424
|
# If true, Rails will verify all foreign keys in the database after loading fixtures.
|
412
425
|
# An error will be raised if there are any foreign key violations, indicating incorrectly
|
413
426
|
# written fixtures.
|
@@ -415,25 +428,18 @@ module ActiveRecord
|
|
415
428
|
singleton_class.attr_accessor :verify_foreign_keys_for_fixtures
|
416
429
|
self.verify_foreign_keys_for_fixtures = false
|
417
430
|
|
418
|
-
##
|
419
|
-
# :singleton-method:
|
420
|
-
# If true, Rails will continue allowing plural association names in where clauses on singular associations
|
421
|
-
# This behavior will be removed in Rails 7.2.
|
422
|
-
singleton_class.attr_accessor :allow_deprecated_singular_associations_name
|
423
|
-
self.allow_deprecated_singular_associations_name = true
|
424
|
-
|
425
431
|
singleton_class.attr_accessor :query_transformers
|
426
432
|
self.query_transformers = []
|
427
433
|
|
428
434
|
##
|
429
|
-
# :singleton-method:
|
435
|
+
# :singleton-method: use_yaml_unsafe_load
|
430
436
|
# Application configurable boolean that instructs the YAML Coder to use
|
431
437
|
# an unsafe load if set to true.
|
432
438
|
singleton_class.attr_accessor :use_yaml_unsafe_load
|
433
439
|
self.use_yaml_unsafe_load = false
|
434
440
|
|
435
441
|
##
|
436
|
-
# :singleton-method:
|
442
|
+
# :singleton-method: raise_int_wider_than_64bit
|
437
443
|
# Application configurable boolean that denotes whether or not to raise
|
438
444
|
# an exception when the PostgreSQLAdapter is provided with an integer that
|
439
445
|
# is wider than signed 64bit representation
|
@@ -441,14 +447,14 @@ module ActiveRecord
|
|
441
447
|
self.raise_int_wider_than_64bit = true
|
442
448
|
|
443
449
|
##
|
444
|
-
# :singleton-method:
|
450
|
+
# :singleton-method: yaml_column_permitted_classes
|
445
451
|
# Application configurable array that provides additional permitted classes
|
446
452
|
# to Psych safe_load in the YAML Coder
|
447
453
|
singleton_class.attr_accessor :yaml_column_permitted_classes
|
448
454
|
self.yaml_column_permitted_classes = [Symbol]
|
449
455
|
|
450
456
|
##
|
451
|
-
# :singleton-method:
|
457
|
+
# :singleton-method: generate_secure_token_on
|
452
458
|
# Controls when to generate a value for <tt>has_secure_token</tt>
|
453
459
|
# declarations. Defaults to <tt>:create</tt>.
|
454
460
|
singleton_class.attr_accessor :generate_secure_token_on
|
@@ -462,6 +468,34 @@ module ActiveRecord
|
|
462
468
|
Marshalling.format_version = value
|
463
469
|
end
|
464
470
|
|
471
|
+
##
|
472
|
+
# :singleton-method: protocol_adapters
|
473
|
+
# Provides a mapping between database protocols/DBMSs and the
|
474
|
+
# underlying database adapter to be used. This is used only by the
|
475
|
+
# <tt>DATABASE_URL</tt> environment variable.
|
476
|
+
#
|
477
|
+
# == Example
|
478
|
+
#
|
479
|
+
# DATABASE_URL="mysql://myuser:mypass@localhost/somedatabase"
|
480
|
+
#
|
481
|
+
# The above URL specifies that MySQL is the desired protocol/DBMS, and the
|
482
|
+
# application configuration can then decide which adapter to use. For this example
|
483
|
+
# the default mapping is from <tt>mysql</tt> to <tt>mysql2</tt>, but <tt>:trilogy</tt>
|
484
|
+
# is also supported.
|
485
|
+
#
|
486
|
+
# ActiveRecord.protocol_adapters.mysql = "mysql2"
|
487
|
+
#
|
488
|
+
# The protocols names are arbitrary, and external database adapters can be
|
489
|
+
# registered and set here.
|
490
|
+
singleton_class.attr_accessor :protocol_adapters
|
491
|
+
self.protocol_adapters = ActiveSupport::InheritableOptions.new(
|
492
|
+
{
|
493
|
+
sqlite: "sqlite3",
|
494
|
+
mysql: "mysql2",
|
495
|
+
postgres: "postgresql",
|
496
|
+
}
|
497
|
+
)
|
498
|
+
|
465
499
|
def self.eager_load!
|
466
500
|
super
|
467
501
|
ActiveRecord::Locking.eager_load!
|
@@ -476,6 +510,53 @@ module ActiveRecord
|
|
476
510
|
def self.disconnect_all!
|
477
511
|
ConnectionAdapters::PoolConfig.disconnect_all!
|
478
512
|
end
|
513
|
+
|
514
|
+
# Registers a block to be called after all the current transactions have been
|
515
|
+
# committed.
|
516
|
+
#
|
517
|
+
# If there is no currently open transaction, the block is called immediately.
|
518
|
+
#
|
519
|
+
# If there are multiple nested transactions, the block is called after the outermost one
|
520
|
+
# has been committed,
|
521
|
+
#
|
522
|
+
# If any of the currently open transactions is rolled back, the block is never called.
|
523
|
+
#
|
524
|
+
# If multiple transactions are open across multiple databases, the block will be invoked
|
525
|
+
# if and once all of them have been committed. But note that nesting transactions across
|
526
|
+
# two distinct databases is a sharding anti-pattern that comes with a world of hurts.
|
527
|
+
def self.after_all_transactions_commit(&block)
|
528
|
+
open_transactions = all_open_transactions
|
529
|
+
|
530
|
+
if open_transactions.empty?
|
531
|
+
yield
|
532
|
+
elsif open_transactions.size == 1
|
533
|
+
open_transactions.first.after_commit(&block)
|
534
|
+
else
|
535
|
+
count = open_transactions.size
|
536
|
+
callback = -> do
|
537
|
+
count -= 1
|
538
|
+
block.call if count.zero?
|
539
|
+
end
|
540
|
+
open_transactions.each do |t|
|
541
|
+
t.after_commit(&callback)
|
542
|
+
end
|
543
|
+
open_transactions = nil # rubocop:disable Lint/UselessAssignment avoid holding it in the closure
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
def self.all_open_transactions # :nodoc:
|
548
|
+
open_transactions = []
|
549
|
+
Base.connection_handler.each_connection_pool do |pool|
|
550
|
+
if active_connection = pool.active_connection
|
551
|
+
current_transaction = active_connection.current_transaction
|
552
|
+
|
553
|
+
if current_transaction.open? && current_transaction.joinable? && !current_transaction.state.invalidated?
|
554
|
+
open_transactions << current_transaction
|
555
|
+
end
|
556
|
+
end
|
557
|
+
end
|
558
|
+
open_transactions
|
559
|
+
end
|
479
560
|
end
|
480
561
|
|
481
562
|
ActiveSupport.on_load(:active_record) do
|