activerecord 8.0.0 → 8.1.4
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 +1381 -241
- data/README.rdoc +2 -2
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/association.rb +35 -17
- data/lib/active_record/associations/association_scope.rb +1 -1
- data/lib/active_record/associations/belongs_to_association.rb +20 -4
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +36 -8
- data/lib/active_record/associations/builder/collection_association.rb +7 -3
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +33 -5
- data/lib/active_record/associations/collection_association.rb +9 -5
- data/lib/active_record/associations/collection_proxy.rb +26 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/foreign_association.rb +3 -1
- data/lib/active_record/associations/has_one_association.rb +1 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/associations/join_dependency.rb +5 -4
- data/lib/active_record/associations/preloader/association.rb +1 -1
- data/lib/active_record/associations/preloader/batch.rb +7 -1
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations.rb +159 -21
- data/lib/active_record/attribute_methods/primary_key.rb +2 -1
- data/lib/active_record/attribute_methods/query.rb +34 -0
- data/lib/active_record/attribute_methods/serialization.rb +19 -6
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +10 -2
- data/lib/active_record/attribute_methods.rb +24 -17
- data/lib/active_record/attributes.rb +40 -26
- data/lib/active_record/autosave_association.rb +22 -12
- data/lib/active_record/base.rb +3 -4
- data/lib/active_record/callbacks.rb +1 -2
- data/lib/active_record/coders/column_serializer.rb +1 -1
- data/lib/active_record/coders/json.rb +16 -6
- data/lib/active_record/coders/yaml_column.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +19 -18
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +16 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +68 -12
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +474 -112
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +68 -41
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -24
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +7 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +31 -35
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +94 -28
- data/lib/active_record/connection_adapters/abstract/transaction.rb +25 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -64
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +133 -40
- data/lib/active_record/connection_adapters/column.rb +14 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +2 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +42 -5
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +40 -25
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +66 -15
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +9 -3
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +8 -2
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +29 -33
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +46 -3
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +21 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +8 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -33
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +70 -32
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +99 -54
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +40 -12
- data/lib/active_record/connection_adapters/sqlite3/column.rb +8 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +39 -23
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +15 -3
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +7 -14
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +68 -37
- data/lib/active_record/connection_adapters/statement_pool.rb +4 -2
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +8 -3
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +16 -2
- data/lib/active_record/connection_adapters.rb +1 -0
- data/lib/active_record/connection_handling.rb +15 -10
- data/lib/active_record/core.rb +44 -12
- data/lib/active_record/counter_cache.rb +36 -9
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/database_configurations/database_config.rb +5 -1
- data/lib/active_record/database_configurations/hash_config.rb +66 -9
- data/lib/active_record/database_configurations/url_config.rb +15 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +19 -19
- data/lib/active_record/disable_joins_association_relation.rb +5 -1
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/encryptable_record.rb +5 -5
- data/lib/active_record/encryption/encrypted_attribute_type.rb +2 -2
- data/lib/active_record/encryption/encrypted_fixtures.rb +12 -7
- data/lib/active_record/encryption/encryptor.rb +39 -25
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +37 -20
- data/lib/active_record/errors.rb +23 -7
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/explain_registry.rb +51 -2
- data/lib/active_record/filter_attribute_handler.rb +76 -0
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/fixtures.rb +2 -2
- data/lib/active_record/future_result.rb +5 -3
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +9 -4
- data/lib/active_record/insert_all.rb +14 -9
- data/lib/active_record/locking/optimistic.rb +7 -0
- data/lib/active_record/locking/pessimistic.rb +5 -0
- data/lib/active_record/log_subscriber.rb +30 -22
- data/lib/active_record/message_pack.rb +13 -0
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +32 -6
- data/lib/active_record/migration/compatibility.rb +34 -24
- data/lib/active_record/migration/default_schema_versions_formatter.rb +30 -0
- data/lib/active_record/migration.rb +31 -21
- data/lib/active_record/model_schema.rb +38 -12
- data/lib/active_record/nested_attributes.rb +10 -6
- data/lib/active_record/persistence.rb +35 -3
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +7 -7
- data/lib/active_record/querying.rb +17 -5
- data/lib/active_record/railtie.rb +35 -6
- data/lib/active_record/railties/controller_runtime.rb +11 -6
- data/lib/active_record/railties/databases.rake +24 -20
- data/lib/active_record/railties/job_checkpoints.rb +15 -0
- data/lib/active_record/railties/job_runtime.rb +10 -11
- data/lib/active_record/reflection.rb +36 -1
- data/lib/active_record/relation/batches.rb +25 -11
- data/lib/active_record/relation/calculations.rb +62 -41
- data/lib/active_record/relation/delegation.rb +0 -1
- data/lib/active_record/relation/finder_methods.rb +76 -45
- data/lib/active_record/relation/merger.rb +4 -2
- data/lib/active_record/relation/predicate_builder/array_handler.rb +3 -1
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -9
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +7 -7
- data/lib/active_record/relation/predicate_builder.rb +10 -8
- data/lib/active_record/relation/query_attribute.rb +4 -2
- data/lib/active_record/relation/query_methods.rb +106 -45
- data/lib/active_record/relation/spawn_methods.rb +6 -6
- data/lib/active_record/relation/where_clause.rb +10 -11
- data/lib/active_record/relation.rb +63 -31
- data/lib/active_record/result.rb +44 -21
- data/lib/active_record/runtime_registry.rb +42 -58
- data/lib/active_record/sanitization.rb +2 -0
- data/lib/active_record/schema.rb +1 -1
- data/lib/active_record/schema_dumper.rb +41 -21
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +48 -19
- data/lib/active_record/statement_cache.rb +16 -12
- data/lib/active_record/store.rb +46 -19
- data/lib/active_record/structured_event_subscriber.rb +85 -0
- data/lib/active_record/table_metadata.rb +5 -20
- data/lib/active_record/tasks/abstract_tasks.rb +83 -0
- data/lib/active_record/tasks/database_tasks.rb +44 -45
- data/lib/active_record/tasks/mysql_database_tasks.rb +4 -56
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -40
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -26
- data/lib/active_record/test_databases.rb +18 -4
- data/lib/active_record/test_fixtures.rb +40 -6
- data/lib/active_record/testing/query_assertions.rb +8 -2
- data/lib/active_record/timestamp.rb +4 -2
- data/lib/active_record/transaction.rb +2 -5
- data/lib/active_record/transactions.rb +58 -32
- data/lib/active_record/type/hash_lookup_type_map.rb +2 -1
- data/lib/active_record/type/internal/timezone.rb +7 -0
- data/lib/active_record/type/json.rb +13 -2
- data/lib/active_record/type/serialized.rb +16 -4
- data/lib/active_record/type/type_map.rb +1 -1
- data/lib/active_record/type_caster/connection.rb +2 -1
- data/lib/active_record/validations/associated.rb +1 -1
- data/lib/active_record.rb +72 -7
- data/lib/arel/alias_predication.rb +2 -0
- 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/crud.rb +8 -11
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/binary.rb +1 -1
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +1 -1
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/predications.rb +1 -3
- data/lib/arel/select_manager.rb +13 -4
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +7 -23
- data/lib/arel.rb +3 -1
- data/lib/rails/generators/active_record/application_record/USAGE +1 -1
- metadata +16 -15
- data/lib/active_record/explain_subscriber.rb +0 -34
- data/lib/active_record/normalization.rb +0 -163
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
class Migration
|
|
5
|
+
# This class is used by the schema dumper to format versions information.
|
|
6
|
+
#
|
|
7
|
+
# The class receives the current +connection+ when initialized.
|
|
8
|
+
class DefaultSchemaVersionsFormatter # :nodoc:
|
|
9
|
+
def initialize(connection)
|
|
10
|
+
@connection = connection
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def format(versions)
|
|
14
|
+
sm_table = connection.quote_table_name(connection.pool.schema_migration.table_name)
|
|
15
|
+
|
|
16
|
+
if versions.is_a?(Array)
|
|
17
|
+
sql = +"INSERT INTO #{sm_table} (version) VALUES\n"
|
|
18
|
+
sql << versions.reverse.map { |v| "(#{connection.quote(v)})" }.join(",\n")
|
|
19
|
+
sql << ";"
|
|
20
|
+
sql
|
|
21
|
+
else
|
|
22
|
+
"INSERT INTO #{sm_table} (version) VALUES (#{connection.quote(versions)});"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
attr_reader :connection
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -18,7 +18,7 @@ module ActiveRecord
|
|
|
18
18
|
# For example the following migration is not reversible.
|
|
19
19
|
# Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
|
|
20
20
|
#
|
|
21
|
-
# class IrreversibleMigrationExample < ActiveRecord::Migration[8.
|
|
21
|
+
# class IrreversibleMigrationExample < ActiveRecord::Migration[8.1]
|
|
22
22
|
# def change
|
|
23
23
|
# create_table :distributors do |t|
|
|
24
24
|
# t.string :zipcode
|
|
@@ -36,7 +36,7 @@ module ActiveRecord
|
|
|
36
36
|
#
|
|
37
37
|
# 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
|
|
38
38
|
#
|
|
39
|
-
# class ReversibleMigrationExample < ActiveRecord::Migration[8.
|
|
39
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[8.1]
|
|
40
40
|
# def up
|
|
41
41
|
# create_table :distributors do |t|
|
|
42
42
|
# t.string :zipcode
|
|
@@ -61,7 +61,7 @@ module ActiveRecord
|
|
|
61
61
|
#
|
|
62
62
|
# 2. Use the #reversible method in <tt>#change</tt> method:
|
|
63
63
|
#
|
|
64
|
-
# class ReversibleMigrationExample < ActiveRecord::Migration[8.
|
|
64
|
+
# class ReversibleMigrationExample < ActiveRecord::Migration[8.1]
|
|
65
65
|
# def change
|
|
66
66
|
# create_table :distributors do |t|
|
|
67
67
|
# t.string :zipcode
|
|
@@ -148,11 +148,10 @@ module ActiveRecord
|
|
|
148
148
|
include ActiveSupport::ActionableError
|
|
149
149
|
|
|
150
150
|
action "Run pending migrations" do
|
|
151
|
-
ActiveRecord::Tasks::DatabaseTasks.
|
|
151
|
+
ActiveRecord::Tasks::DatabaseTasks.migrate_all
|
|
152
152
|
|
|
153
153
|
if ActiveRecord.dump_schema_after_migration
|
|
154
|
-
|
|
155
|
-
ActiveRecord::Tasks::DatabaseTasks.dump_schema(connection.pool.db_config)
|
|
154
|
+
ActiveRecord::Tasks::DatabaseTasks.dump_all
|
|
156
155
|
end
|
|
157
156
|
end
|
|
158
157
|
|
|
@@ -247,7 +246,7 @@ module ActiveRecord
|
|
|
247
246
|
#
|
|
248
247
|
# Example of a simple migration:
|
|
249
248
|
#
|
|
250
|
-
# class AddSsl < ActiveRecord::Migration[8.
|
|
249
|
+
# class AddSsl < ActiveRecord::Migration[8.1]
|
|
251
250
|
# def up
|
|
252
251
|
# add_column :accounts, :ssl_enabled, :boolean, default: true
|
|
253
252
|
# end
|
|
@@ -267,7 +266,7 @@ module ActiveRecord
|
|
|
267
266
|
#
|
|
268
267
|
# Example of a more complex migration that also needs to initialize data:
|
|
269
268
|
#
|
|
270
|
-
# class AddSystemSettings < ActiveRecord::Migration[8.
|
|
269
|
+
# class AddSystemSettings < ActiveRecord::Migration[8.1]
|
|
271
270
|
# def up
|
|
272
271
|
# create_table :system_settings do |t|
|
|
273
272
|
# t.string :name
|
|
@@ -396,7 +395,7 @@ module ActiveRecord
|
|
|
396
395
|
# $ bin/rails generate migration add_fieldname_to_tablename fieldname:string
|
|
397
396
|
#
|
|
398
397
|
# This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
|
|
399
|
-
# class AddFieldnameToTablename < ActiveRecord::Migration[8.
|
|
398
|
+
# class AddFieldnameToTablename < ActiveRecord::Migration[8.1]
|
|
400
399
|
# def change
|
|
401
400
|
# add_column :tablenames, :fieldname, :string
|
|
402
401
|
# end
|
|
@@ -422,7 +421,7 @@ module ActiveRecord
|
|
|
422
421
|
#
|
|
423
422
|
# Not all migrations change the schema. Some just fix the data:
|
|
424
423
|
#
|
|
425
|
-
# class RemoveEmptyTags < ActiveRecord::Migration[8.
|
|
424
|
+
# class RemoveEmptyTags < ActiveRecord::Migration[8.1]
|
|
426
425
|
# def up
|
|
427
426
|
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
|
|
428
427
|
# end
|
|
@@ -435,7 +434,7 @@ module ActiveRecord
|
|
|
435
434
|
#
|
|
436
435
|
# Others remove columns when they migrate up instead of down:
|
|
437
436
|
#
|
|
438
|
-
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.
|
|
437
|
+
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.1]
|
|
439
438
|
# def up
|
|
440
439
|
# remove_column :items, :incomplete_items_count
|
|
441
440
|
# remove_column :items, :completed_items_count
|
|
@@ -449,7 +448,7 @@ module ActiveRecord
|
|
|
449
448
|
#
|
|
450
449
|
# And sometimes you need to do something in SQL not abstracted directly by migrations:
|
|
451
450
|
#
|
|
452
|
-
# class MakeJoinUnique < ActiveRecord::Migration[8.
|
|
451
|
+
# class MakeJoinUnique < ActiveRecord::Migration[8.1]
|
|
453
452
|
# def up
|
|
454
453
|
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
|
|
455
454
|
# end
|
|
@@ -466,7 +465,7 @@ module ActiveRecord
|
|
|
466
465
|
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
|
|
467
466
|
# latest column data from after the new column was added. Example:
|
|
468
467
|
#
|
|
469
|
-
# class AddPeopleSalary < ActiveRecord::Migration[8.
|
|
468
|
+
# class AddPeopleSalary < ActiveRecord::Migration[8.1]
|
|
470
469
|
# def up
|
|
471
470
|
# add_column :people, :salary, :integer
|
|
472
471
|
# Person.reset_column_information
|
|
@@ -528,7 +527,7 @@ module ActiveRecord
|
|
|
528
527
|
# To define a reversible migration, define the +change+ method in your
|
|
529
528
|
# migration like this:
|
|
530
529
|
#
|
|
531
|
-
# class TenderloveMigration < ActiveRecord::Migration[8.
|
|
530
|
+
# class TenderloveMigration < ActiveRecord::Migration[8.1]
|
|
532
531
|
# def change
|
|
533
532
|
# create_table(:horses) do |t|
|
|
534
533
|
# t.column :content, :text
|
|
@@ -558,7 +557,7 @@ module ActiveRecord
|
|
|
558
557
|
# can't execute inside a transaction though, and for these situations
|
|
559
558
|
# you can turn the automatic transactions off.
|
|
560
559
|
#
|
|
561
|
-
# class ChangeEnum < ActiveRecord::Migration[8.
|
|
560
|
+
# class ChangeEnum < ActiveRecord::Migration[8.1]
|
|
562
561
|
# disable_ddl_transaction!
|
|
563
562
|
#
|
|
564
563
|
# def up
|
|
@@ -571,6 +570,7 @@ module ActiveRecord
|
|
|
571
570
|
class Migration
|
|
572
571
|
autoload :CommandRecorder, "active_record/migration/command_recorder"
|
|
573
572
|
autoload :Compatibility, "active_record/migration/compatibility"
|
|
573
|
+
autoload :DefaultSchemaVersionsFormatter, "active_record/migration/default_schema_versions_formatter"
|
|
574
574
|
autoload :JoinTable, "active_record/migration/join_table"
|
|
575
575
|
autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
|
|
576
576
|
autoload :DefaultStrategy, "active_record/migration/default_strategy"
|
|
@@ -747,7 +747,7 @@ module ActiveRecord
|
|
|
747
747
|
private
|
|
748
748
|
def any_schema_needs_update?
|
|
749
749
|
!db_configs_in_current_env.all? do |db_config|
|
|
750
|
-
Tasks::DatabaseTasks.schema_up_to_date?(db_config
|
|
750
|
+
Tasks::DatabaseTasks.schema_up_to_date?(db_config)
|
|
751
751
|
end
|
|
752
752
|
end
|
|
753
753
|
|
|
@@ -782,6 +782,11 @@ module ActiveRecord
|
|
|
782
782
|
system("bin/rails db:test:prepare")
|
|
783
783
|
end
|
|
784
784
|
end
|
|
785
|
+
|
|
786
|
+
def respond_to_missing?(method, include_private = false)
|
|
787
|
+
return false if nearest_delegate == delegate
|
|
788
|
+
nearest_delegate.respond_to?(method, include_private)
|
|
789
|
+
end
|
|
785
790
|
end
|
|
786
791
|
|
|
787
792
|
def disable_ddl_transaction # :nodoc:
|
|
@@ -819,7 +824,7 @@ module ActiveRecord
|
|
|
819
824
|
# and create the table 'apples' on the way up, and the reverse
|
|
820
825
|
# on the way down.
|
|
821
826
|
#
|
|
822
|
-
# class FixTLMigration < ActiveRecord::Migration[8.
|
|
827
|
+
# class FixTLMigration < ActiveRecord::Migration[8.1]
|
|
823
828
|
# def change
|
|
824
829
|
# revert do
|
|
825
830
|
# create_table(:horses) do |t|
|
|
@@ -838,7 +843,7 @@ module ActiveRecord
|
|
|
838
843
|
#
|
|
839
844
|
# require_relative "20121212123456_tenderlove_migration"
|
|
840
845
|
#
|
|
841
|
-
# class FixupTLMigration < ActiveRecord::Migration[8.
|
|
846
|
+
# class FixupTLMigration < ActiveRecord::Migration[8.1]
|
|
842
847
|
# def change
|
|
843
848
|
# revert TenderloveMigration
|
|
844
849
|
#
|
|
@@ -889,7 +894,7 @@ module ActiveRecord
|
|
|
889
894
|
# when the three columns 'first_name', 'last_name' and 'full_name' exist,
|
|
890
895
|
# even when migrating down:
|
|
891
896
|
#
|
|
892
|
-
# class SplitNameMigration < ActiveRecord::Migration[8.
|
|
897
|
+
# class SplitNameMigration < ActiveRecord::Migration[8.1]
|
|
893
898
|
# def change
|
|
894
899
|
# add_column :users, :first_name, :string
|
|
895
900
|
# add_column :users, :last_name, :string
|
|
@@ -917,7 +922,7 @@ module ActiveRecord
|
|
|
917
922
|
# In the following example, the new column +published+ will be given
|
|
918
923
|
# the value +true+ for all existing records.
|
|
919
924
|
#
|
|
920
|
-
# class AddPublishedToPosts < ActiveRecord::Migration[8.
|
|
925
|
+
# class AddPublishedToPosts < ActiveRecord::Migration[8.1]
|
|
921
926
|
# def change
|
|
922
927
|
# add_column :posts, :published, :boolean, default: false
|
|
923
928
|
# up_only do
|
|
@@ -1170,6 +1175,10 @@ module ActiveRecord
|
|
|
1170
1175
|
def command_recorder
|
|
1171
1176
|
CommandRecorder.new(connection)
|
|
1172
1177
|
end
|
|
1178
|
+
|
|
1179
|
+
def respond_to_missing?(method, include_private = false)
|
|
1180
|
+
execution_strategy.respond_to?(method, include_private) || super
|
|
1181
|
+
end
|
|
1173
1182
|
end
|
|
1174
1183
|
|
|
1175
1184
|
# MigrationProxy is used to defer loading of the actual migration classes
|
|
@@ -1529,7 +1538,8 @@ module ActiveRecord
|
|
|
1529
1538
|
return if down? && !migrated.include?(migration.version.to_i)
|
|
1530
1539
|
return if up? && migrated.include?(migration.version.to_i)
|
|
1531
1540
|
|
|
1532
|
-
|
|
1541
|
+
message = up? ? "Migrating to" : "Reverting"
|
|
1542
|
+
Base.logger.info "#{message} #{migration.name} (#{migration.version})" if Base.logger
|
|
1533
1543
|
|
|
1534
1544
|
ddl_transaction(migration) do
|
|
1535
1545
|
migration.migrate(@direction)
|
|
@@ -48,7 +48,7 @@ module ActiveRecord
|
|
|
48
48
|
# way of creating a namespace for tables in a shared database. By default, the prefix is the
|
|
49
49
|
# empty string.
|
|
50
50
|
#
|
|
51
|
-
# If you are
|
|
51
|
+
# If you are organizing your models within modules you can add a prefix to the models within
|
|
52
52
|
# a namespace by defining a singleton method in the parent module called table_name_prefix which
|
|
53
53
|
# returns your chosen prefix.
|
|
54
54
|
|
|
@@ -65,7 +65,7 @@ module ActiveRecord
|
|
|
65
65
|
# Works like +table_name_prefix=+, but appends instead of prepends (set to "_basecamp" gives "projects_basecamp",
|
|
66
66
|
# "people_basecamp"). By default, the suffix is the empty string.
|
|
67
67
|
#
|
|
68
|
-
# If you are
|
|
68
|
+
# If you are organizing your models within modules, you can add a suffix to the models within
|
|
69
69
|
# a namespace by defining a singleton method in the parent module called table_name_suffix which
|
|
70
70
|
# returns your chosen suffix.
|
|
71
71
|
|
|
@@ -113,17 +113,19 @@ module ActiveRecord
|
|
|
113
113
|
# :singleton-method: implicit_order_column
|
|
114
114
|
# :call-seq: implicit_order_column
|
|
115
115
|
#
|
|
116
|
-
# The name of the column records are ordered by if no explicit order clause
|
|
116
|
+
# The name of the column(s) records are ordered by if no explicit order clause
|
|
117
117
|
# is used during an ordered finder call. If not set the primary key is used.
|
|
118
118
|
|
|
119
119
|
##
|
|
120
120
|
# :singleton-method: implicit_order_column=
|
|
121
121
|
# :call-seq: implicit_order_column=(column_name)
|
|
122
122
|
#
|
|
123
|
-
# Sets the column to sort records by when no explicit order clause is used
|
|
124
|
-
# during an ordered finder call. Useful
|
|
125
|
-
# auto-incrementing integer
|
|
126
|
-
#
|
|
123
|
+
# Sets the column(s) to sort records by when no explicit order clause is used
|
|
124
|
+
# during an ordered finder call. Useful for models where the primary key isn't an
|
|
125
|
+
# auto-incrementing integer (such as UUID).
|
|
126
|
+
#
|
|
127
|
+
# By default, records are subsorted by primary key to ensure deterministic results.
|
|
128
|
+
# To disable this subsort behavior, set `implicit_order_column` to `["column_name", nil]`.
|
|
127
129
|
|
|
128
130
|
##
|
|
129
131
|
# :singleton-method: immutable_strings_by_default=
|
|
@@ -179,6 +181,7 @@ module ActiveRecord
|
|
|
179
181
|
self.protected_environments = ["production"]
|
|
180
182
|
|
|
181
183
|
self.ignored_columns = [].freeze
|
|
184
|
+
self.only_columns = [].freeze
|
|
182
185
|
|
|
183
186
|
delegate :type_for_attribute, :column_for_attribute, to: :class
|
|
184
187
|
|
|
@@ -332,6 +335,12 @@ module ActiveRecord
|
|
|
332
335
|
@ignored_columns || superclass.ignored_columns
|
|
333
336
|
end
|
|
334
337
|
|
|
338
|
+
# The list of columns names the model should allow. Only columns are used to define
|
|
339
|
+
# attribute accessors, and are referenced in SQL queries.
|
|
340
|
+
def only_columns
|
|
341
|
+
@only_columns || superclass.only_columns
|
|
342
|
+
end
|
|
343
|
+
|
|
335
344
|
# Sets the columns names the model should ignore. Ignored columns won't have attribute
|
|
336
345
|
# accessors defined, and won't be referenced in SQL queries.
|
|
337
346
|
#
|
|
@@ -364,10 +373,17 @@ module ActiveRecord
|
|
|
364
373
|
# user = Project.create!(name: "First Project")
|
|
365
374
|
# user.category # => raises NoMethodError
|
|
366
375
|
def ignored_columns=(columns)
|
|
376
|
+
check_model_columns(@only_columns.present?)
|
|
367
377
|
reload_schema_from_cache
|
|
368
378
|
@ignored_columns = columns.map(&:to_s).freeze
|
|
369
379
|
end
|
|
370
380
|
|
|
381
|
+
def only_columns=(columns)
|
|
382
|
+
check_model_columns(@ignored_columns.present?)
|
|
383
|
+
reload_schema_from_cache
|
|
384
|
+
@only_columns = columns.map(&:to_s).freeze
|
|
385
|
+
end
|
|
386
|
+
|
|
371
387
|
def sequence_name
|
|
372
388
|
if base_class?
|
|
373
389
|
@sequence_name ||= reset_sequence_name
|
|
@@ -419,7 +435,7 @@ module ActiveRecord
|
|
|
419
435
|
|
|
420
436
|
def attributes_builder # :nodoc:
|
|
421
437
|
@attributes_builder ||= begin
|
|
422
|
-
defaults = _default_attributes.except(*(column_names -
|
|
438
|
+
defaults = _default_attributes.except(*(column_names - Array(primary_key)))
|
|
423
439
|
ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
|
|
424
440
|
end
|
|
425
441
|
end
|
|
@@ -488,7 +504,7 @@ module ActiveRecord
|
|
|
488
504
|
# and columns used for single table inheritance have been removed.
|
|
489
505
|
def content_columns
|
|
490
506
|
@content_columns ||= columns.reject do |c|
|
|
491
|
-
c.name
|
|
507
|
+
Array(primary_key).include?(c.name) ||
|
|
492
508
|
c.name == inheritance_column ||
|
|
493
509
|
c.name.end_with?("_id", "_count")
|
|
494
510
|
end.freeze
|
|
@@ -501,7 +517,7 @@ module ActiveRecord
|
|
|
501
517
|
# when just after creating a table you want to populate it with some default
|
|
502
518
|
# values, e.g.:
|
|
503
519
|
#
|
|
504
|
-
# class CreateJobLevels < ActiveRecord::Migration[8.
|
|
520
|
+
# class CreateJobLevels < ActiveRecord::Migration[8.1]
|
|
505
521
|
# def up
|
|
506
522
|
# create_table :job_levels do |t|
|
|
507
523
|
# t.integer :id
|
|
@@ -577,6 +593,7 @@ module ActiveRecord
|
|
|
577
593
|
child_class.reload_schema_from_cache(false)
|
|
578
594
|
child_class.class_eval do
|
|
579
595
|
@ignored_columns = nil
|
|
596
|
+
@only_columns = nil
|
|
580
597
|
end
|
|
581
598
|
end
|
|
582
599
|
|
|
@@ -590,7 +607,11 @@ module ActiveRecord
|
|
|
590
607
|
end
|
|
591
608
|
|
|
592
609
|
columns_hash = schema_cache.columns_hash(table_name)
|
|
593
|
-
|
|
610
|
+
if only_columns.present?
|
|
611
|
+
columns_hash = columns_hash.slice(*only_columns)
|
|
612
|
+
elsif ignored_columns.present?
|
|
613
|
+
columns_hash = columns_hash.except(*ignored_columns)
|
|
614
|
+
end
|
|
594
615
|
@columns_hash = columns_hash.freeze
|
|
595
616
|
|
|
596
617
|
_default_attributes # Precompute to cache DB-dependent attribute types
|
|
@@ -620,7 +641,8 @@ module ActiveRecord
|
|
|
620
641
|
end
|
|
621
642
|
|
|
622
643
|
def type_for_column(connection, column)
|
|
623
|
-
|
|
644
|
+
# TODO: Remove the need for a connection after we release 8.1.
|
|
645
|
+
type = column.fetch_cast_type(connection)
|
|
624
646
|
|
|
625
647
|
if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
|
|
626
648
|
type = type.to_immutable_string
|
|
@@ -628,6 +650,10 @@ module ActiveRecord
|
|
|
628
650
|
|
|
629
651
|
type
|
|
630
652
|
end
|
|
653
|
+
|
|
654
|
+
def check_model_columns(columns_present)
|
|
655
|
+
raise ArgumentError, "You can not use both only_columns and ignored_columns in the same model." if columns_present
|
|
656
|
+
end
|
|
631
657
|
end
|
|
632
658
|
end
|
|
633
659
|
end
|
|
@@ -103,7 +103,7 @@ module ActiveRecord
|
|
|
103
103
|
#
|
|
104
104
|
# class Member < ActiveRecord::Base
|
|
105
105
|
# has_many :posts
|
|
106
|
-
# accepts_nested_attributes_for :posts
|
|
106
|
+
# accepts_nested_attributes_for :posts, allow_destroy: true
|
|
107
107
|
# end
|
|
108
108
|
#
|
|
109
109
|
# You can now set or update attributes on the associated posts through
|
|
@@ -112,7 +112,8 @@ module ActiveRecord
|
|
|
112
112
|
#
|
|
113
113
|
# For each hash that does _not_ have an <tt>id</tt> key a new record will
|
|
114
114
|
# be instantiated, unless the hash also contains a <tt>_destroy</tt> key
|
|
115
|
-
# that evaluates to +true
|
|
115
|
+
# that evaluates to +true+ and the <tt>:allow_destroy</tt> option is
|
|
116
|
+
# enabled.
|
|
116
117
|
#
|
|
117
118
|
# params = { member: {
|
|
118
119
|
# name: 'joe', posts_attributes: [
|
|
@@ -313,8 +314,9 @@ module ActiveRecord
|
|
|
313
314
|
# that checks whether a record should be built for a certain attribute
|
|
314
315
|
# hash. The hash is passed to the supplied Proc or the method
|
|
315
316
|
# and it should return either +true+ or +false+. When no +:reject_if+
|
|
316
|
-
# is specified, a record will be built for all attribute hashes
|
|
317
|
-
#
|
|
317
|
+
# is specified, a record will be built for all attribute hashes, unless
|
|
318
|
+
# the <tt>:allow_destroy</tt> option is enabled and the hash has a
|
|
319
|
+
# <tt>_destroy</tt> value that evaluates to true.
|
|
318
320
|
# Passing <tt>:all_blank</tt> instead of a Proc will create a proc
|
|
319
321
|
# that will reject a record where all the attributes are blank excluding
|
|
320
322
|
# any value for +_destroy+.
|
|
@@ -387,6 +389,8 @@ module ActiveRecord
|
|
|
387
389
|
generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
|
|
388
390
|
silence_redefinition_of_method :#{association_name}_attributes=
|
|
389
391
|
def #{association_name}_attributes=(attributes)
|
|
392
|
+
association = association(:#{association_name})
|
|
393
|
+
deprecated_associations_api_guard(association, __method__)
|
|
390
394
|
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
|
|
391
395
|
end
|
|
392
396
|
eoruby
|
|
@@ -494,8 +498,6 @@ module ActiveRecord
|
|
|
494
498
|
raise ArgumentError, "Hash or Array expected for `#{association_name}` attributes, got #{attributes_collection.class.name}"
|
|
495
499
|
end
|
|
496
500
|
|
|
497
|
-
check_record_limit!(options[:limit], attributes_collection)
|
|
498
|
-
|
|
499
501
|
if attributes_collection.is_a? Hash
|
|
500
502
|
keys = attributes_collection.keys
|
|
501
503
|
attributes_collection = if keys.include?("id") || keys.include?(:id)
|
|
@@ -505,6 +507,8 @@ module ActiveRecord
|
|
|
505
507
|
end
|
|
506
508
|
end
|
|
507
509
|
|
|
510
|
+
check_record_limit!(options[:limit], attributes_collection)
|
|
511
|
+
|
|
508
512
|
association = association(association_name)
|
|
509
513
|
|
|
510
514
|
existing_records = if association.loaded?
|
|
@@ -492,7 +492,9 @@ module ActiveRecord
|
|
|
492
492
|
becoming.instance_variable_set(:@attributes, @attributes)
|
|
493
493
|
becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
|
|
494
494
|
becoming.instance_variable_set(:@new_record, new_record?)
|
|
495
|
+
becoming.instance_variable_set(:@previously_new_record, previously_new_record?)
|
|
495
496
|
becoming.instance_variable_set(:@destroyed, destroyed?)
|
|
497
|
+
becoming.instance_variable_set(:@marked_for_destruction, marked_for_destruction?)
|
|
496
498
|
becoming.errors.copy!(errors)
|
|
497
499
|
end
|
|
498
500
|
|
|
@@ -581,8 +583,8 @@ module ActiveRecord
|
|
|
581
583
|
end
|
|
582
584
|
|
|
583
585
|
# Equivalent to <code>update_columns(name => value)</code>.
|
|
584
|
-
def update_column(name, value)
|
|
585
|
-
update_columns(name => value)
|
|
586
|
+
def update_column(name, value, touch: nil)
|
|
587
|
+
update_columns(name => value, touch: touch)
|
|
586
588
|
end
|
|
587
589
|
|
|
588
590
|
# Updates the attributes directly in the database issuing an UPDATE SQL
|
|
@@ -596,11 +598,25 @@ module ActiveRecord
|
|
|
596
598
|
#
|
|
597
599
|
# * \Validations are skipped.
|
|
598
600
|
# * \Callbacks are skipped.
|
|
599
|
-
# * +updated_at+/+updated_on+ are
|
|
601
|
+
# * +updated_at+/+updated_on+ are updated if the +touch+ option is set to +true+.
|
|
600
602
|
# * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
|
|
601
603
|
#
|
|
602
604
|
# This method raises an ActiveRecord::ActiveRecordError when called on new
|
|
603
605
|
# objects, or when at least one of the attributes is marked as readonly.
|
|
606
|
+
#
|
|
607
|
+
# ==== Parameters
|
|
608
|
+
#
|
|
609
|
+
# * <tt>:touch</tt> option - Touch the timestamp columns when updating.
|
|
610
|
+
# * If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
|
|
611
|
+
#
|
|
612
|
+
# ==== Examples
|
|
613
|
+
#
|
|
614
|
+
# # Update a single attribute.
|
|
615
|
+
# user.update_columns(last_request_at: Time.current)
|
|
616
|
+
#
|
|
617
|
+
# # Update with touch option.
|
|
618
|
+
# user.update_columns(last_request_at: Time.current, touch: true)
|
|
619
|
+
|
|
604
620
|
def update_columns(attributes)
|
|
605
621
|
raise ActiveRecordError, "cannot update a new record" if new_record?
|
|
606
622
|
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
|
@@ -612,6 +628,15 @@ module ActiveRecord
|
|
|
612
628
|
verify_readonly_attribute(name) || name
|
|
613
629
|
end
|
|
614
630
|
|
|
631
|
+
touch = attributes.delete("touch")
|
|
632
|
+
if touch
|
|
633
|
+
names = touch if touch != true
|
|
634
|
+
names = Array.wrap(names)
|
|
635
|
+
options = names.extract_options!
|
|
636
|
+
touch_updates = self.class.touch_attributes_with_time(*names, **options)
|
|
637
|
+
attributes.with_defaults!(touch_updates) unless touch_updates.empty?
|
|
638
|
+
end
|
|
639
|
+
|
|
615
640
|
update_constraints = _query_constraints_hash
|
|
616
641
|
attributes = attributes.each_with_object({}) do |(k, v), h|
|
|
617
642
|
h[k] = @attributes.write_cast_value(k, v)
|
|
@@ -640,8 +665,15 @@ module ActiveRecord
|
|
|
640
665
|
# This means that any other modified attributes will still be dirty.
|
|
641
666
|
# Validations and callbacks are skipped. Supports the +touch+ option from
|
|
642
667
|
# +update_counters+, see that for more.
|
|
668
|
+
#
|
|
669
|
+
# This method raises an ActiveRecord::ActiveRecordError when called on new
|
|
670
|
+
# objects, or when at least one of the attributes is marked as readonly.
|
|
671
|
+
#
|
|
643
672
|
# Returns +self+.
|
|
644
673
|
def increment!(attribute, by = 1, touch: nil)
|
|
674
|
+
raise ActiveRecordError, "cannot update a new record" if new_record?
|
|
675
|
+
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
|
676
|
+
|
|
645
677
|
increment(attribute, by)
|
|
646
678
|
change = public_send(attribute) - (public_send(:"#{attribute}_in_database") || 0)
|
|
647
679
|
self.class.update_counters(id, attribute => change, touch: touch)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
module ActiveRecord
|
|
4
4
|
# = Active Record Query Cache
|
|
5
5
|
class QueryCache
|
|
6
|
+
# ActiveRecord::Base extends this module, so these methods are available in models.
|
|
6
7
|
module ClassMethods
|
|
7
8
|
# Enable the query cache within the block if Active Record is configured.
|
|
8
9
|
# If it's not, it will execute the given block.
|
|
@@ -20,11 +21,15 @@ module ActiveRecord
|
|
|
20
21
|
end
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
#
|
|
24
|
-
#
|
|
24
|
+
# Runs the block with the query cache disabled.
|
|
25
|
+
#
|
|
26
|
+
# If the query cache was enabled before the block was executed, it is
|
|
27
|
+
# enabled again after it.
|
|
25
28
|
#
|
|
26
|
-
# Set <tt>dirties: false</tt> to prevent query caches on all connections
|
|
27
|
-
# (By default, write operations
|
|
29
|
+
# Set <tt>dirties: false</tt> to prevent query caches on all connections
|
|
30
|
+
# from being cleared by write operations. (By default, write operations
|
|
31
|
+
# dirty all connections' query caches in case they are replicas whose
|
|
32
|
+
# cache would now be outdated.)
|
|
28
33
|
def uncached(dirties: true, &block)
|
|
29
34
|
if connected? || !configurations.empty?
|
|
30
35
|
connection_pool.disable_query_cache(dirties: dirties, &block)
|
|
@@ -34,22 +39,24 @@ module ActiveRecord
|
|
|
34
39
|
end
|
|
35
40
|
end
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
module ExecutorHooks # :nodoc:
|
|
43
|
+
def self.run
|
|
44
|
+
ActiveRecord::Base.connection_handler.each_connection_pool.reject(&:query_cache_enabled).each do |pool|
|
|
45
|
+
next if pool.db_config&.query_cache == false
|
|
46
|
+
pool.enable_query_cache!
|
|
47
|
+
end
|
|
41
48
|
end
|
|
42
|
-
end
|
|
43
49
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
def self.complete(pools)
|
|
51
|
+
pools.each do |pool|
|
|
52
|
+
pool.disable_query_cache!
|
|
53
|
+
pool.clear_query_cache
|
|
54
|
+
end
|
|
48
55
|
end
|
|
49
56
|
end
|
|
50
57
|
|
|
51
|
-
def self.install_executor_hooks(executor = ActiveSupport::Executor)
|
|
52
|
-
executor.register_hook(
|
|
58
|
+
def self.install_executor_hooks(executor = ActiveSupport::Executor) # :nodoc:
|
|
59
|
+
executor.register_hook(ExecutorHooks)
|
|
53
60
|
end
|
|
54
61
|
end
|
|
55
62
|
end
|
|
@@ -28,6 +28,10 @@ module ActiveRecord
|
|
|
28
28
|
# * +database+
|
|
29
29
|
# * +source_location+
|
|
30
30
|
#
|
|
31
|
+
# WARNING: Calculating the +source_location+ of a query can be slow, so you should consider its impact if using it in a production environment.
|
|
32
|
+
#
|
|
33
|
+
# Also see {config.active_record.verbose_query_logs}[https://guides.rubyonrails.org/debugging_rails_applications.html#verbose-query-logs].
|
|
34
|
+
#
|
|
31
35
|
# Action Controller adds default tags when loaded:
|
|
32
36
|
#
|
|
33
37
|
# * +controller+
|
|
@@ -65,7 +69,7 @@ module ActiveRecord
|
|
|
65
69
|
#
|
|
66
70
|
# Tag comments can be prepended to the query:
|
|
67
71
|
#
|
|
68
|
-
#
|
|
72
|
+
# config.active_record.query_log_tags_prepend_comment = true
|
|
69
73
|
#
|
|
70
74
|
# For applications where the content will not change during the lifetime of
|
|
71
75
|
# the request or job execution, the tags can be cached for reuse in every query:
|
|
@@ -153,11 +157,7 @@ module ActiveRecord
|
|
|
153
157
|
end
|
|
154
158
|
|
|
155
159
|
def query_source_location # :nodoc:
|
|
156
|
-
|
|
157
|
-
frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
|
|
158
|
-
return frame if frame
|
|
159
|
-
end
|
|
160
|
-
nil
|
|
160
|
+
LogSubscriber.backtrace_cleaner.first_clean_frame
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
|
|
@@ -211,7 +211,7 @@ module ActiveRecord
|
|
|
211
211
|
end
|
|
212
212
|
|
|
213
213
|
def escape_sql_comment(content)
|
|
214
|
-
# Sanitize a string to appear within
|
|
214
|
+
# Sanitize a string to appear within an SQL comment
|
|
215
215
|
# For compatibility, this also surrounding "/*+", "/*", and "*/"
|
|
216
216
|
# characters, possibly with single surrounding space.
|
|
217
217
|
# Then follows that by replacing any internal "*/" or "/ *" with
|
|
@@ -17,12 +17,24 @@ module ActiveRecord
|
|
|
17
17
|
:and, :or, :annotate, :optimizer_hints, :extending,
|
|
18
18
|
:having, :create_with, :distinct, :references, :none, :unscope, :merge, :except, :only,
|
|
19
19
|
:count, :average, :minimum, :maximum, :sum, :calculate,
|
|
20
|
-
:pluck, :pick, :ids, :async_ids, :strict_loading, :excluding, :without, :
|
|
20
|
+
:pluck, :pick, :ids, :async_ids, :strict_loading, :excluding, :without, :with_recursive,
|
|
21
21
|
:async_count, :async_average, :async_minimum, :async_maximum, :async_sum, :async_pluck, :async_pick,
|
|
22
22
|
:insert, :insert_all, :insert!, :insert_all!, :upsert, :upsert_all
|
|
23
23
|
].freeze # :nodoc:
|
|
24
24
|
delegate(*QUERYING_METHODS, to: :all)
|
|
25
25
|
|
|
26
|
+
# Add a Common Table Expression (CTE) that you can then reference within another SELECT statement.
|
|
27
|
+
#
|
|
28
|
+
# See ActiveRecord::QueryMethods#with for more information.
|
|
29
|
+
#
|
|
30
|
+
# When given a block, and the Object#with core extension is loaded, this
|
|
31
|
+
# delegates to it instead, temporarily setting the given attributes on the
|
|
32
|
+
# class for the duration of the block and restoring them afterwards.
|
|
33
|
+
def with(...)
|
|
34
|
+
return super if block_given? && defined?(super)
|
|
35
|
+
all.with(...)
|
|
36
|
+
end
|
|
37
|
+
|
|
26
38
|
# Executes a custom SQL query against your database and returns all the results. The results will
|
|
27
39
|
# be returned as an array, with the requested columns encapsulated as attributes of the model you call
|
|
28
40
|
# this method from. For example, if you call <tt>Product.find_by_sql</tt>, then the results will be returned in
|
|
@@ -46,8 +58,8 @@ module ActiveRecord
|
|
|
46
58
|
# Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
|
|
47
59
|
# Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
|
|
48
60
|
#
|
|
49
|
-
# Note that building your own SQL query string from user input may expose your application to
|
|
50
|
-
# injection attacks
|
|
61
|
+
# Note that building your own SQL query string from user input {may expose your application to
|
|
62
|
+
# injection attacks}[https://guides.rubyonrails.org/security.html#sql-injection].
|
|
51
63
|
def find_by_sql(sql, binds = [], preparable: nil, allow_retry: false, &block)
|
|
52
64
|
result = with_connection do |c|
|
|
53
65
|
_query_by_sql(c, sql, binds, preparable: preparable, allow_retry: allow_retry)
|
|
@@ -55,7 +67,7 @@ module ActiveRecord
|
|
|
55
67
|
_load_from_sql(result, &block)
|
|
56
68
|
end
|
|
57
69
|
|
|
58
|
-
# Same as
|
|
70
|
+
# Same as #find_by_sql but perform the query asynchronously and returns an ActiveRecord::Promise.
|
|
59
71
|
def async_find_by_sql(sql, binds = [], preparable: nil, allow_retry: false, &block)
|
|
60
72
|
with_connection do |c|
|
|
61
73
|
_query_by_sql(c, sql, binds, preparable: preparable, allow_retry: allow_retry, async: true)
|
|
@@ -112,7 +124,7 @@ module ActiveRecord
|
|
|
112
124
|
end
|
|
113
125
|
end
|
|
114
126
|
|
|
115
|
-
# Same as
|
|
127
|
+
# Same as #count_by_sql but perform the query asynchronously and returns an ActiveRecord::Promise.
|
|
116
128
|
def async_count_by_sql(sql)
|
|
117
129
|
with_connection do |c|
|
|
118
130
|
c.select_value(sanitize_sql(sql), "#{name} Count", async: true).then(&:to_i)
|