activerecord 8.0.3 → 8.1.0.beta1
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 +427 -522
- data/README.rdoc +1 -1
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +17 -4
- 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_proxy.rb +22 -4
- data/lib/active_record/associations/deprecation.rb +88 -0
- data/lib/active_record/associations/errors.rb +3 -0
- data/lib/active_record/associations/join_dependency.rb +2 -0
- data/lib/active_record/associations/preloader/branch.rb +1 -0
- data/lib/active_record/associations.rb +159 -21
- data/lib/active_record/attribute_methods/serialization.rb +16 -3
- data/lib/active_record/attribute_methods.rb +1 -1
- data/lib/active_record/attributes.rb +3 -0
- data/lib/active_record/autosave_association.rb +1 -1
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/coders/json.rb +14 -5
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +15 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +51 -12
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +382 -51
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +26 -30
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +25 -18
- 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 +26 -34
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +85 -22
- data/lib/active_record/connection_adapters/abstract/transaction.rb +16 -3
- data/lib/active_record/connection_adapters/abstract_adapter.rb +66 -14
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +43 -11
- data/lib/active_record/connection_adapters/column.rb +17 -4
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +4 -4
- 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 +26 -4
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +27 -22
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +18 -23
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -2
- 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/schema_creation.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +8 -21
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +65 -30
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +74 -38
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +10 -5
- data/lib/active_record/connection_adapters/schema_cache.rb +2 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +37 -25
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -8
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -30
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +4 -3
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -1
- data/lib/active_record/connection_adapters.rb +1 -0
- data/lib/active_record/core.rb +5 -4
- data/lib/active_record/counter_cache.rb +33 -8
- data/lib/active_record/database_configurations/database_config.rb +5 -1
- data/lib/active_record/database_configurations/hash_config.rb +50 -9
- data/lib/active_record/database_configurations/url_config.rb +13 -3
- data/lib/active_record/database_configurations.rb +7 -3
- data/lib/active_record/delegated_type.rb +1 -1
- data/lib/active_record/dynamic_matchers.rb +54 -69
- data/lib/active_record/encryption/encryptable_record.rb +4 -4
- data/lib/active_record/encryption/encrypted_attribute_type.rb +1 -1
- data/lib/active_record/encryption/scheme.rb +1 -1
- data/lib/active_record/enum.rb +24 -8
- data/lib/active_record/errors.rb +23 -7
- data/lib/active_record/explain_registry.rb +0 -1
- data/lib/active_record/filter_attribute_handler.rb +73 -0
- data/lib/active_record/fixtures.rb +2 -2
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +1 -1
- data/lib/active_record/insert_all.rb +12 -7
- 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 +1 -5
- data/lib/active_record/middleware/shard_selector.rb +34 -17
- data/lib/active_record/migration/command_recorder.rb +14 -1
- 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 +26 -16
- data/lib/active_record/model_schema.rb +10 -7
- data/lib/active_record/nested_attributes.rb +2 -0
- data/lib/active_record/persistence.rb +34 -3
- data/lib/active_record/query_cache.rb +22 -15
- data/lib/active_record/query_logs.rb +3 -7
- data/lib/active_record/railtie.rb +32 -3
- data/lib/active_record/railties/databases.rake +16 -4
- 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 +42 -3
- data/lib/active_record/relation/batches.rb +26 -12
- data/lib/active_record/relation/calculations.rb +20 -9
- data/lib/active_record/relation/delegation.rb +0 -1
- data/lib/active_record/relation/finder_methods.rb +27 -11
- data/lib/active_record/relation/merger.rb +2 -2
- data/lib/active_record/relation/predicate_builder.rb +2 -2
- data/lib/active_record/relation/query_attribute.rb +3 -1
- data/lib/active_record/relation/query_methods.rb +39 -29
- data/lib/active_record/relation/where_clause.rb +1 -10
- data/lib/active_record/relation.rb +25 -13
- data/lib/active_record/result.rb +44 -21
- data/lib/active_record/sanitization.rb +2 -0
- data/lib/active_record/schema_dumper.rb +12 -10
- data/lib/active_record/scoping.rb +0 -1
- data/lib/active_record/signed_id.rb +43 -15
- data/lib/active_record/statement_cache.rb +13 -9
- data/lib/active_record/store.rb +44 -19
- data/lib/active_record/tasks/abstract_tasks.rb +76 -0
- data/lib/active_record/tasks/database_tasks.rb +2 -21
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -40
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -39
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -26
- data/lib/active_record/test_databases.rb +10 -2
- data/lib/active_record/test_fixtures.rb +27 -2
- 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 +32 -10
- 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 +15 -2
- data/lib/active_record/type/serialized.rb +11 -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 +65 -3
- data/lib/arel/alias_predication.rb +2 -0
- data/lib/arel/crud.rb +6 -11
- data/lib/arel/nodes/count.rb +2 -2
- data/lib/arel/nodes/function.rb +4 -10
- data/lib/arel/nodes/named_function.rb +2 -2
- data/lib/arel/nodes/node.rb +1 -1
- data/lib/arel/nodes.rb +0 -2
- data/lib/arel/select_manager.rb +7 -2
- data/lib/arel/visitors/dot.rb +0 -3
- data/lib/arel/visitors/postgresql.rb +55 -0
- data/lib/arel/visitors/sqlite.rb +55 -8
- data/lib/arel/visitors/to_sql.rb +3 -21
- data/lib/arel.rb +3 -1
- metadata +13 -9
- data/lib/active_record/normalization.rb +0 -163
@@ -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
|
@@ -246,7 +246,7 @@ module ActiveRecord
|
|
246
246
|
#
|
247
247
|
# Example of a simple migration:
|
248
248
|
#
|
249
|
-
# class AddSsl < ActiveRecord::Migration[8.
|
249
|
+
# class AddSsl < ActiveRecord::Migration[8.1]
|
250
250
|
# def up
|
251
251
|
# add_column :accounts, :ssl_enabled, :boolean, default: true
|
252
252
|
# end
|
@@ -266,7 +266,7 @@ module ActiveRecord
|
|
266
266
|
#
|
267
267
|
# Example of a more complex migration that also needs to initialize data:
|
268
268
|
#
|
269
|
-
# class AddSystemSettings < ActiveRecord::Migration[8.
|
269
|
+
# class AddSystemSettings < ActiveRecord::Migration[8.1]
|
270
270
|
# def up
|
271
271
|
# create_table :system_settings do |t|
|
272
272
|
# t.string :name
|
@@ -395,7 +395,7 @@ module ActiveRecord
|
|
395
395
|
# $ bin/rails generate migration add_fieldname_to_tablename fieldname:string
|
396
396
|
#
|
397
397
|
# This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
|
398
|
-
# class AddFieldnameToTablename < ActiveRecord::Migration[8.
|
398
|
+
# class AddFieldnameToTablename < ActiveRecord::Migration[8.1]
|
399
399
|
# def change
|
400
400
|
# add_column :tablenames, :fieldname, :string
|
401
401
|
# end
|
@@ -421,7 +421,7 @@ module ActiveRecord
|
|
421
421
|
#
|
422
422
|
# Not all migrations change the schema. Some just fix the data:
|
423
423
|
#
|
424
|
-
# class RemoveEmptyTags < ActiveRecord::Migration[8.
|
424
|
+
# class RemoveEmptyTags < ActiveRecord::Migration[8.1]
|
425
425
|
# def up
|
426
426
|
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
|
427
427
|
# end
|
@@ -434,7 +434,7 @@ module ActiveRecord
|
|
434
434
|
#
|
435
435
|
# Others remove columns when they migrate up instead of down:
|
436
436
|
#
|
437
|
-
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.
|
437
|
+
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.1]
|
438
438
|
# def up
|
439
439
|
# remove_column :items, :incomplete_items_count
|
440
440
|
# remove_column :items, :completed_items_count
|
@@ -448,7 +448,7 @@ module ActiveRecord
|
|
448
448
|
#
|
449
449
|
# And sometimes you need to do something in SQL not abstracted directly by migrations:
|
450
450
|
#
|
451
|
-
# class MakeJoinUnique < ActiveRecord::Migration[8.
|
451
|
+
# class MakeJoinUnique < ActiveRecord::Migration[8.1]
|
452
452
|
# def up
|
453
453
|
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
|
454
454
|
# end
|
@@ -465,7 +465,7 @@ module ActiveRecord
|
|
465
465
|
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
|
466
466
|
# latest column data from after the new column was added. Example:
|
467
467
|
#
|
468
|
-
# class AddPeopleSalary < ActiveRecord::Migration[8.
|
468
|
+
# class AddPeopleSalary < ActiveRecord::Migration[8.1]
|
469
469
|
# def up
|
470
470
|
# add_column :people, :salary, :integer
|
471
471
|
# Person.reset_column_information
|
@@ -527,7 +527,7 @@ module ActiveRecord
|
|
527
527
|
# To define a reversible migration, define the +change+ method in your
|
528
528
|
# migration like this:
|
529
529
|
#
|
530
|
-
# class TenderloveMigration < ActiveRecord::Migration[8.
|
530
|
+
# class TenderloveMigration < ActiveRecord::Migration[8.1]
|
531
531
|
# def change
|
532
532
|
# create_table(:horses) do |t|
|
533
533
|
# t.column :content, :text
|
@@ -557,7 +557,7 @@ module ActiveRecord
|
|
557
557
|
# can't execute inside a transaction though, and for these situations
|
558
558
|
# you can turn the automatic transactions off.
|
559
559
|
#
|
560
|
-
# class ChangeEnum < ActiveRecord::Migration[8.
|
560
|
+
# class ChangeEnum < ActiveRecord::Migration[8.1]
|
561
561
|
# disable_ddl_transaction!
|
562
562
|
#
|
563
563
|
# def up
|
@@ -570,6 +570,7 @@ module ActiveRecord
|
|
570
570
|
class Migration
|
571
571
|
autoload :CommandRecorder, "active_record/migration/command_recorder"
|
572
572
|
autoload :Compatibility, "active_record/migration/compatibility"
|
573
|
+
autoload :DefaultSchemaVersionsFormatter, "active_record/migration/default_schema_versions_formatter"
|
573
574
|
autoload :JoinTable, "active_record/migration/join_table"
|
574
575
|
autoload :ExecutionStrategy, "active_record/migration/execution_strategy"
|
575
576
|
autoload :DefaultStrategy, "active_record/migration/default_strategy"
|
@@ -781,6 +782,11 @@ module ActiveRecord
|
|
781
782
|
system("bin/rails db:test:prepare")
|
782
783
|
end
|
783
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
|
784
790
|
end
|
785
791
|
|
786
792
|
def disable_ddl_transaction # :nodoc:
|
@@ -818,7 +824,7 @@ module ActiveRecord
|
|
818
824
|
# and create the table 'apples' on the way up, and the reverse
|
819
825
|
# on the way down.
|
820
826
|
#
|
821
|
-
# class FixTLMigration < ActiveRecord::Migration[8.
|
827
|
+
# class FixTLMigration < ActiveRecord::Migration[8.1]
|
822
828
|
# def change
|
823
829
|
# revert do
|
824
830
|
# create_table(:horses) do |t|
|
@@ -837,7 +843,7 @@ module ActiveRecord
|
|
837
843
|
#
|
838
844
|
# require_relative "20121212123456_tenderlove_migration"
|
839
845
|
#
|
840
|
-
# class FixupTLMigration < ActiveRecord::Migration[8.
|
846
|
+
# class FixupTLMigration < ActiveRecord::Migration[8.1]
|
841
847
|
# def change
|
842
848
|
# revert TenderloveMigration
|
843
849
|
#
|
@@ -888,7 +894,7 @@ module ActiveRecord
|
|
888
894
|
# when the three columns 'first_name', 'last_name' and 'full_name' exist,
|
889
895
|
# even when migrating down:
|
890
896
|
#
|
891
|
-
# class SplitNameMigration < ActiveRecord::Migration[8.
|
897
|
+
# class SplitNameMigration < ActiveRecord::Migration[8.1]
|
892
898
|
# def change
|
893
899
|
# add_column :users, :first_name, :string
|
894
900
|
# add_column :users, :last_name, :string
|
@@ -916,7 +922,7 @@ module ActiveRecord
|
|
916
922
|
# In the following example, the new column +published+ will be given
|
917
923
|
# the value +true+ for all existing records.
|
918
924
|
#
|
919
|
-
# class AddPublishedToPosts < ActiveRecord::Migration[8.
|
925
|
+
# class AddPublishedToPosts < ActiveRecord::Migration[8.1]
|
920
926
|
# def change
|
921
927
|
# add_column :posts, :published, :boolean, default: false
|
922
928
|
# up_only do
|
@@ -1169,6 +1175,10 @@ module ActiveRecord
|
|
1169
1175
|
def command_recorder
|
1170
1176
|
CommandRecorder.new(connection)
|
1171
1177
|
end
|
1178
|
+
|
1179
|
+
def respond_to_missing?(method, include_private = false)
|
1180
|
+
execution_strategy.respond_to?(method, include_private) || super
|
1181
|
+
end
|
1172
1182
|
end
|
1173
1183
|
|
1174
1184
|
# MigrationProxy is used to defer loading of the actual migration classes
|
@@ -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=
|
@@ -501,7 +503,7 @@ module ActiveRecord
|
|
501
503
|
# when just after creating a table you want to populate it with some default
|
502
504
|
# values, e.g.:
|
503
505
|
#
|
504
|
-
# class CreateJobLevels < ActiveRecord::Migration[8.
|
506
|
+
# class CreateJobLevels < ActiveRecord::Migration[8.1]
|
505
507
|
# def up
|
506
508
|
# create_table :job_levels do |t|
|
507
509
|
# t.integer :id
|
@@ -620,7 +622,8 @@ module ActiveRecord
|
|
620
622
|
end
|
621
623
|
|
622
624
|
def type_for_column(connection, column)
|
623
|
-
|
625
|
+
# TODO: Remove the need for a connection after we release 8.1.
|
626
|
+
type = column.fetch_cast_type(connection)
|
624
627
|
|
625
628
|
if immutable_strings_by_default && type.respond_to?(:to_immutable_string)
|
626
629
|
type = type.to_immutable_string
|
@@ -387,6 +387,8 @@ module ActiveRecord
|
|
387
387
|
generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
|
388
388
|
silence_redefinition_of_method :#{association_name}_attributes=
|
389
389
|
def #{association_name}_attributes=(attributes)
|
390
|
+
association = association(:#{association_name})
|
391
|
+
deprecated_associations_api_guard(association, __method__)
|
390
392
|
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
|
391
393
|
end
|
392
394
|
eoruby
|
@@ -492,6 +492,7 @@ 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?)
|
496
497
|
becoming.errors.copy!(errors)
|
497
498
|
end
|
@@ -581,8 +582,8 @@ module ActiveRecord
|
|
581
582
|
end
|
582
583
|
|
583
584
|
# Equivalent to <code>update_columns(name => value)</code>.
|
584
|
-
def update_column(name, value)
|
585
|
-
update_columns(name => value)
|
585
|
+
def update_column(name, value, touch: nil)
|
586
|
+
update_columns(name => value, touch: touch)
|
586
587
|
end
|
587
588
|
|
588
589
|
# Updates the attributes directly in the database issuing an UPDATE SQL
|
@@ -596,11 +597,25 @@ module ActiveRecord
|
|
596
597
|
#
|
597
598
|
# * \Validations are skipped.
|
598
599
|
# * \Callbacks are skipped.
|
599
|
-
# * +updated_at+/+updated_on+ are
|
600
|
+
# * +updated_at+/+updated_on+ are updated if the +touch+ option is set to +true+.
|
600
601
|
# * However, attributes are serialized with the same rules as ActiveRecord::Relation#update_all
|
601
602
|
#
|
602
603
|
# This method raises an ActiveRecord::ActiveRecordError when called on new
|
603
604
|
# objects, or when at least one of the attributes is marked as readonly.
|
605
|
+
#
|
606
|
+
# ==== Parameters
|
607
|
+
#
|
608
|
+
# * <tt>:touch</tt> option - Touch the timestamp columns when updating.
|
609
|
+
# * If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
|
610
|
+
#
|
611
|
+
# ==== Examples
|
612
|
+
#
|
613
|
+
# # Update a single attribute.
|
614
|
+
# user.update_columns(last_request_at: Time.current)
|
615
|
+
#
|
616
|
+
# # Update with touch option.
|
617
|
+
# user.update_columns(last_request_at: Time.current, touch: true)
|
618
|
+
|
604
619
|
def update_columns(attributes)
|
605
620
|
raise ActiveRecordError, "cannot update a new record" if new_record?
|
606
621
|
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
@@ -612,6 +627,15 @@ module ActiveRecord
|
|
612
627
|
verify_readonly_attribute(name) || name
|
613
628
|
end
|
614
629
|
|
630
|
+
touch = attributes.delete("touch")
|
631
|
+
if touch
|
632
|
+
names = touch if touch != true
|
633
|
+
names = Array.wrap(names)
|
634
|
+
options = names.extract_options!
|
635
|
+
touch_updates = self.class.touch_attributes_with_time(*names, **options)
|
636
|
+
attributes.with_defaults!(touch_updates) unless touch_updates.empty?
|
637
|
+
end
|
638
|
+
|
615
639
|
update_constraints = _query_constraints_hash
|
616
640
|
attributes = attributes.each_with_object({}) do |(k, v), h|
|
617
641
|
h[k] = @attributes.write_cast_value(k, v)
|
@@ -640,8 +664,15 @@ module ActiveRecord
|
|
640
664
|
# This means that any other modified attributes will still be dirty.
|
641
665
|
# Validations and callbacks are skipped. Supports the +touch+ option from
|
642
666
|
# +update_counters+, see that for more.
|
667
|
+
#
|
668
|
+
# This method raises an ActiveRecord::ActiveRecordError when called on new
|
669
|
+
# objects, or when at least one of the attributes is marked as readonly.
|
670
|
+
#
|
643
671
|
# Returns +self+.
|
644
672
|
def increment!(attribute, by = 1, touch: nil)
|
673
|
+
raise ActiveRecordError, "cannot update a new record" if new_record?
|
674
|
+
raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
|
675
|
+
|
645
676
|
increment(attribute, by)
|
646
677
|
change = public_send(attribute) - (public_send(:"#{attribute}_in_database") || 0)
|
647
678
|
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
|
@@ -69,7 +69,7 @@ module ActiveRecord
|
|
69
69
|
#
|
70
70
|
# Tag comments can be prepended to the query:
|
71
71
|
#
|
72
|
-
#
|
72
|
+
# config.active_record.query_log_tags_prepend_comment = true
|
73
73
|
#
|
74
74
|
# For applications where the content will not change during the lifetime of
|
75
75
|
# the request or job execution, the tags can be cached for reuse in every query:
|
@@ -157,11 +157,7 @@ module ActiveRecord
|
|
157
157
|
end
|
158
158
|
|
159
159
|
def query_source_location # :nodoc:
|
160
|
-
|
161
|
-
frame = LogSubscriber.backtrace_cleaner.clean_frame(location)
|
162
|
-
return frame if frame
|
163
|
-
end
|
164
|
-
nil
|
160
|
+
LogSubscriber.backtrace_cleaner.first_clean_frame
|
165
161
|
end
|
166
162
|
|
167
163
|
ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
|
@@ -215,7 +211,7 @@ module ActiveRecord
|
|
215
211
|
end
|
216
212
|
|
217
213
|
def escape_sql_comment(content)
|
218
|
-
# Sanitize a string to appear within
|
214
|
+
# Sanitize a string to appear within an SQL comment
|
219
215
|
# For compatibility, this also surrounding "/*+", "/*", and "*/"
|
220
216
|
# characters, possibly with single surrounding space.
|
221
217
|
# Then follows that by replacing any internal "*/" or "/ *" with
|
@@ -35,9 +35,12 @@ module ActiveRecord
|
|
35
35
|
config.active_record.query_log_tags = [ :application ]
|
36
36
|
config.active_record.query_log_tags_format = :legacy
|
37
37
|
config.active_record.cache_query_log_tags = false
|
38
|
+
config.active_record.query_log_tags_prepend_comment = false
|
38
39
|
config.active_record.raise_on_assign_to_attr_readonly = false
|
39
40
|
config.active_record.belongs_to_required_validates_foreign_key = true
|
40
41
|
config.active_record.generate_secure_token_on = :create
|
42
|
+
config.active_record.use_legacy_signed_id_verifier = :generate_and_verify
|
43
|
+
config.active_record.deprecated_associations_options = { mode: :warn, backtrace: false }
|
41
44
|
|
42
45
|
config.active_record.queues = ActiveSupport::InheritableOptions.new
|
43
46
|
|
@@ -229,10 +232,12 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
229
232
|
:query_log_tags,
|
230
233
|
:query_log_tags_format,
|
231
234
|
:cache_query_log_tags,
|
235
|
+
:query_log_tags_prepend_comment,
|
232
236
|
:sqlite3_adapter_strict_strings_by_default,
|
233
237
|
:check_schema_cache_dump_version,
|
234
238
|
:use_schema_cache_dump,
|
235
239
|
:postgresql_adapter_decode_dates,
|
240
|
+
:use_legacy_signed_id_verifier,
|
236
241
|
)
|
237
242
|
|
238
243
|
configs_used_in_other_initializers.each do |k, v|
|
@@ -274,6 +279,13 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
274
279
|
end
|
275
280
|
end
|
276
281
|
|
282
|
+
initializer "active_record.job_checkpoints" do
|
283
|
+
require "active_record/railties/job_checkpoints"
|
284
|
+
ActiveSupport.on_load(:active_job_continuable) do
|
285
|
+
prepend ActiveRecord::Railties::JobCheckpoints
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
277
289
|
initializer "active_record.set_reloader_hooks" do
|
278
290
|
ActiveSupport.on_load(:active_record) do
|
279
291
|
ActiveSupport::Reloader.before_class_unload do
|
@@ -319,9 +331,22 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
319
331
|
end
|
320
332
|
end
|
321
333
|
|
322
|
-
initializer "active_record.
|
323
|
-
|
324
|
-
|
334
|
+
initializer "active_record.filter_attributes_as_log_parameters" do |app|
|
335
|
+
ActiveRecord::FilterAttributeHandler.new(app).enable
|
336
|
+
end
|
337
|
+
|
338
|
+
initializer "active_record.configure_message_verifiers" do |app|
|
339
|
+
ActiveRecord.message_verifiers = app.message_verifiers
|
340
|
+
|
341
|
+
use_legacy_signed_id_verifier = app.config.active_record.use_legacy_signed_id_verifier
|
342
|
+
legacy_options = { digest: "SHA256", serializer: JSON, url_safe: true }
|
343
|
+
|
344
|
+
if use_legacy_signed_id_verifier == :generate_and_verify
|
345
|
+
app.message_verifiers.prepend { |salt| legacy_options if salt == "active_record/signed_id" }
|
346
|
+
elsif use_legacy_signed_id_verifier == :verify
|
347
|
+
app.message_verifiers.rotate { |salt| legacy_options if salt == "active_record/signed_id" }
|
348
|
+
elsif use_legacy_signed_id_verifier
|
349
|
+
raise ArgumentError, "Unrecognized value for config.active_record.use_legacy_signed_id_verifier: #{use_legacy_signed_id_verifier.inspect}"
|
325
350
|
end
|
326
351
|
end
|
327
352
|
|
@@ -387,6 +412,10 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
387
412
|
if app.config.active_record.cache_query_log_tags
|
388
413
|
ActiveRecord::QueryLogs.cache_query_log_tags = true
|
389
414
|
end
|
415
|
+
|
416
|
+
if app.config.active_record.query_log_tags_prepend_comment
|
417
|
+
ActiveRecord::QueryLogs.prepend_comment = true
|
418
|
+
end
|
390
419
|
end
|
391
420
|
end
|
392
421
|
end
|
@@ -163,6 +163,18 @@ db_namespace = namespace :db do
|
|
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
|
+
namespace :reset do
|
167
|
+
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
168
|
+
desc "Drop and recreate the #{name} database using migrations"
|
169
|
+
task name => :load_config do
|
170
|
+
db_namespace["drop:#{name}"].invoke
|
171
|
+
db_namespace["create:#{name}"].invoke
|
172
|
+
db_namespace["schema:dump:#{name}"].invoke
|
173
|
+
db_namespace["migrate:#{name}"].invoke
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
166
178
|
desc 'Run the "up" for a given migration VERSION.'
|
167
179
|
task up: :load_config do
|
168
180
|
ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:up")
|
@@ -333,7 +345,7 @@ db_namespace = namespace :db do
|
|
333
345
|
pending_migrations << pool.migration_context.open.pending_migrations
|
334
346
|
end
|
335
347
|
|
336
|
-
pending_migrations
|
348
|
+
pending_migrations.flatten!
|
337
349
|
|
338
350
|
if pending_migrations.any?
|
339
351
|
puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
|
@@ -454,12 +466,12 @@ db_namespace = namespace :db do
|
|
454
466
|
|
455
467
|
desc "Load a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) into the database"
|
456
468
|
task load: [:load_config, :check_protected_environments] do
|
457
|
-
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(
|
469
|
+
ActiveRecord::Tasks::DatabaseTasks.load_schema_current(nil, ENV["SCHEMA"])
|
458
470
|
end
|
459
471
|
|
460
472
|
namespace :dump do
|
461
473
|
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
462
|
-
desc "Create a database schema file (either db/schema.rb or db/structure.sql, depending on
|
474
|
+
desc "Create a database schema file (either db/schema.rb or db/structure.sql, depending on configuration) for #{name} database"
|
463
475
|
task name => :load_config do
|
464
476
|
ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(name: name) do |pool|
|
465
477
|
db_config = pool.db_config
|
@@ -474,7 +486,7 @@ db_namespace = namespace :db do
|
|
474
486
|
namespace :load do
|
475
487
|
ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
|
476
488
|
desc "Load a database schema file (either db/schema.rb or db/structure.sql, depending on configuration) into the #{name} database"
|
477
|
-
task name =>
|
489
|
+
task name => [:load_config, :check_protected_environments] do
|
478
490
|
ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(name: name) do |pool|
|
479
491
|
db_config = pool.db_config
|
480
492
|
ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ENV["SCHEMA_FORMAT"] || db_config.schema_format)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Railties # :nodoc:
|
5
|
+
module JobCheckpoints # :nodoc:
|
6
|
+
def checkpoint!
|
7
|
+
if ActiveRecord.all_open_transactions.any?
|
8
|
+
raise ActiveJob::Continuation::CheckpointError, "Cannot checkpoint job with open transactions"
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -5,19 +5,18 @@ require "active_record/runtime_registry"
|
|
5
5
|
module ActiveRecord
|
6
6
|
module Railties # :nodoc:
|
7
7
|
module JobRuntime # :nodoc:
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
result
|
16
|
-
end
|
17
|
-
else
|
18
|
-
super
|
8
|
+
def instrument(operation, payload = {}, &block) # :nodoc:
|
9
|
+
if operation == :perform && block
|
10
|
+
super(operation, payload) do
|
11
|
+
db_runtime_before_perform = ActiveRecord::RuntimeRegistry.sql_runtime
|
12
|
+
result = block.call
|
13
|
+
payload[:db_runtime] = ActiveRecord::RuntimeRegistry.sql_runtime - db_runtime_before_perform
|
14
|
+
result
|
19
15
|
end
|
16
|
+
else
|
17
|
+
super
|
20
18
|
end
|
19
|
+
end
|
21
20
|
end
|
22
21
|
end
|
23
22
|
end
|