activerecord 7.0.6 → 7.1.1
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 +1424 -1390
- data/MIT-LICENSE +1 -1
- data/README.rdoc +15 -16
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +18 -3
- data/lib/active_record/associations/association_scope.rb +16 -9
- data/lib/active_record/associations/belongs_to_association.rb +14 -6
- data/lib/active_record/associations/builder/association.rb +3 -3
- data/lib/active_record/associations/builder/belongs_to.rb +21 -8
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- data/lib/active_record/associations/builder/singular_association.rb +4 -0
- data/lib/active_record/associations/collection_association.rb +16 -10
- data/lib/active_record/associations/collection_proxy.rb +20 -10
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +20 -13
- data/lib/active_record/associations/has_many_through_association.rb +10 -6
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/join_dependency.rb +10 -8
- data/lib/active_record/associations/preloader/association.rb +27 -6
- data/lib/active_record/associations/preloader.rb +13 -10
- data/lib/active_record/associations/singular_association.rb +6 -8
- data/lib/active_record/associations/through_association.rb +22 -11
- data/lib/active_record/associations.rb +295 -199
- data/lib/active_record/attribute_assignment.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
- data/lib/active_record/attribute_methods/dirty.rb +40 -26
- data/lib/active_record/attribute_methods/primary_key.rb +76 -24
- data/lib/active_record/attribute_methods/query.rb +28 -16
- data/lib/active_record/attribute_methods/read.rb +18 -5
- data/lib/active_record/attribute_methods/serialization.rb +150 -31
- data/lib/active_record/attribute_methods/write.rb +3 -3
- data/lib/active_record/attribute_methods.rb +105 -21
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +60 -18
- data/lib/active_record/base.rb +7 -2
- data/lib/active_record/callbacks.rb +10 -24
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -42
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +63 -43
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +128 -32
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +60 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +289 -124
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +496 -102
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +214 -113
- data/lib/active_record/connection_adapters/column.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -144
- data/lib/active_record/connection_adapters/mysql/quoting.rb +21 -14
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +18 -13
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
- data/lib/active_record/connection_adapters/pool_config.rb +14 -5
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +71 -40
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +15 -8
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +349 -55
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +338 -176
- data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +45 -39
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +9 -5
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -9
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +210 -83
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +71 -94
- data/lib/active_record/core.rb +136 -148
- data/lib/active_record/counter_cache.rb +46 -25
- data/lib/active_record/database_configurations/database_config.rb +9 -3
- data/lib/active_record/database_configurations/hash_config.rb +22 -12
- data/lib/active_record/database_configurations/url_config.rb +17 -11
- data/lib/active_record/database_configurations.rb +86 -33
- data/lib/active_record/delegated_type.rb +8 -3
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +2 -0
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
- data/lib/active_record/encryption/config.rb +25 -1
- data/lib/active_record/encryption/configurable.rb +12 -19
- data/lib/active_record/encryption/context.rb +10 -3
- data/lib/active_record/encryption/contexts.rb +5 -1
- data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
- data/lib/active_record/encryption/encryptable_record.rb +36 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +17 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -54
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
- data/lib/active_record/encryption/key_generator.rb +12 -1
- data/lib/active_record/encryption/message_serializer.rb +2 -0
- data/lib/active_record/encryption/properties.rb +3 -3
- data/lib/active_record/encryption/scheme.rb +19 -22
- data/lib/active_record/encryption.rb +1 -0
- data/lib/active_record/enum.rb +113 -26
- data/lib/active_record/errors.rb +108 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +29 -8
- data/lib/active_record/fixtures.rb +119 -71
- data/lib/active_record/future_result.rb +30 -5
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +55 -8
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +120 -30
- data/lib/active_record/locking/pessimistic.rb +5 -2
- data/lib/active_record/log_subscriber.rb +29 -12
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
- data/lib/active_record/middleware/database_selector.rb +5 -7
- data/lib/active_record/middleware/shard_selector.rb +3 -1
- data/lib/active_record/migration/command_recorder.rb +104 -5
- data/lib/active_record/migration/compatibility.rb +142 -58
- data/lib/active_record/migration/default_strategy.rb +23 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration.rb +265 -112
- data/lib/active_record/model_schema.rb +60 -40
- data/lib/active_record/nested_attributes.rb +21 -3
- data/lib/active_record/normalization.rb +159 -0
- data/lib/active_record/persistence.rb +187 -35
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +3 -21
- data/lib/active_record/query_logs.rb +77 -52
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +15 -2
- data/lib/active_record/railtie.rb +109 -47
- data/lib/active_record/railties/controller_runtime.rb +12 -8
- data/lib/active_record/railties/databases.rake +139 -145
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +32 -5
- data/lib/active_record/reflection.rb +162 -44
- data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
- data/lib/active_record/relation/batches.rb +190 -61
- data/lib/active_record/relation/calculations.rb +160 -63
- data/lib/active_record/relation/delegation.rb +22 -8
- data/lib/active_record/relation/finder_methods.rb +77 -16
- data/lib/active_record/relation/merger.rb +2 -0
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +27 -16
- data/lib/active_record/relation/query_attribute.rb +25 -1
- data/lib/active_record/relation/query_methods.rb +378 -70
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +76 -35
- data/lib/active_record/result.rb +19 -5
- data/lib/active_record/runtime_registry.rb +10 -1
- data/lib/active_record/sanitization.rb +51 -11
- data/lib/active_record/schema.rb +2 -3
- data/lib/active_record/schema_dumper.rb +46 -7
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +15 -5
- data/lib/active_record/scoping/named.rb +2 -2
- data/lib/active_record/scoping.rb +2 -1
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/signed_id.rb +7 -5
- data/lib/active_record/store.rb +8 -8
- data/lib/active_record/suppressor.rb +3 -1
- data/lib/active_record/table_metadata.rb +11 -2
- data/lib/active_record/tasks/database_tasks.rb +127 -105
- data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_fixtures.rb +113 -96
- data/lib/active_record/timestamp.rb +27 -15
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +39 -13
- data/lib/active_record/type/adapter_specific_registry.rb +1 -8
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +4 -0
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +47 -2
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +121 -16
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/nodes/and.rb +4 -0
- data/lib/arel/nodes/binary.rb +6 -1
- data/lib/arel/nodes/bound_sql_literal.rb +61 -0
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/homogeneous_in.rb +0 -8
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes.rb +4 -0
- data/lib/arel/predications.rb +2 -0
- data/lib/arel/table.rb +9 -5
- data/lib/arel/visitors/mysql.rb +8 -1
- data/lib/arel/visitors/to_sql.rb +81 -17
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +16 -2
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- metadata +50 -15
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -63
@@ -57,6 +57,36 @@ module ActiveRecord
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
# Builds an object (or multiple objects) and returns either the built object or a list of built
|
61
|
+
# objects.
|
62
|
+
#
|
63
|
+
# The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
|
64
|
+
# attributes on the objects that are to be built.
|
65
|
+
#
|
66
|
+
# ==== Examples
|
67
|
+
# # Build a single new object
|
68
|
+
# User.build(first_name: 'Jamie')
|
69
|
+
#
|
70
|
+
# # Build an Array of new objects
|
71
|
+
# User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
|
72
|
+
#
|
73
|
+
# # Build a single object and pass it into a block to set other attributes.
|
74
|
+
# User.build(first_name: 'Jamie') do |u|
|
75
|
+
# u.is_admin = false
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# # Building an Array of new objects using a block, where the block is executed for each object:
|
79
|
+
# User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
|
80
|
+
# u.is_admin = false
|
81
|
+
# end
|
82
|
+
def build(attributes = nil, &block)
|
83
|
+
if attributes.is_a?(Array)
|
84
|
+
attributes.collect { |attr| build(attr, &block) }
|
85
|
+
else
|
86
|
+
new(attributes, &block)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
60
90
|
# Inserts a single record into the database in a single SQL INSERT
|
61
91
|
# statement. It does not instantiate any models nor does it trigger
|
62
92
|
# Active Record callbacks or validations. Though passed values
|
@@ -92,7 +122,7 @@ module ActiveRecord
|
|
92
122
|
# clause entirely.
|
93
123
|
#
|
94
124
|
# You can also pass an SQL string if you need more control on the return values
|
95
|
-
# (for example, <tt>returning: "id, name as new_name"</tt>).
|
125
|
+
# (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
|
96
126
|
#
|
97
127
|
# [:unique_by]
|
98
128
|
# (PostgreSQL and SQLite only) By default rows are considered to be unique
|
@@ -102,7 +132,7 @@ module ActiveRecord
|
|
102
132
|
#
|
103
133
|
# Consider a Book model where no duplicate ISBNs make sense, but if any
|
104
134
|
# row has an existing id, or is not unique by another unique index,
|
105
|
-
#
|
135
|
+
# ActiveRecord::RecordNotUnique is raised.
|
106
136
|
#
|
107
137
|
# Unique indexes can be identified by columns or name:
|
108
138
|
#
|
@@ -164,7 +194,7 @@ module ActiveRecord
|
|
164
194
|
# The +attributes+ parameter is an Array of Hashes. Every Hash determines
|
165
195
|
# the attributes for a single row and must have the same keys.
|
166
196
|
#
|
167
|
-
# Raises
|
197
|
+
# Raises ActiveRecord::RecordNotUnique if any rows violate a
|
168
198
|
# unique index on the table. In that case, no rows are inserted.
|
169
199
|
#
|
170
200
|
# To skip duplicate rows, see #insert_all. To replace them, see #upsert_all.
|
@@ -182,7 +212,7 @@ module ActiveRecord
|
|
182
212
|
# clause entirely.
|
183
213
|
#
|
184
214
|
# You can also pass an SQL string if you need more control on the return values
|
185
|
-
# (for example, <tt>returning: "id, name as new_name"</tt>).
|
215
|
+
# (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
|
186
216
|
#
|
187
217
|
# [:record_timestamps]
|
188
218
|
# By default, automatic setting of timestamp columns is controlled by
|
@@ -219,8 +249,8 @@ module ActiveRecord
|
|
219
249
|
# go through Active Record's type casting and serialization.
|
220
250
|
#
|
221
251
|
# See #upsert_all for documentation.
|
222
|
-
def upsert(attributes,
|
223
|
-
upsert_all([ attributes ],
|
252
|
+
def upsert(attributes, **kwargs)
|
253
|
+
upsert_all([ attributes ], **kwargs)
|
224
254
|
end
|
225
255
|
|
226
256
|
# Updates or inserts (upserts) multiple records into the database in a
|
@@ -248,7 +278,7 @@ module ActiveRecord
|
|
248
278
|
# clause entirely.
|
249
279
|
#
|
250
280
|
# You can also pass an SQL string if you need more control on the return values
|
251
|
-
# (for example, <tt>returning: "id, name as new_name"</tt>).
|
281
|
+
# (for example, <tt>returning: Arel.sql("id, name as new_name")</tt>).
|
252
282
|
#
|
253
283
|
# [:unique_by]
|
254
284
|
# (PostgreSQL and SQLite only) By default rows are considered to be unique
|
@@ -258,7 +288,7 @@ module ActiveRecord
|
|
258
288
|
#
|
259
289
|
# Consider a Book model where no duplicate ISBNs make sense, but if any
|
260
290
|
# row has an existing id, or is not unique by another unique index,
|
261
|
-
#
|
291
|
+
# ActiveRecord::RecordNotUnique is raised.
|
262
292
|
#
|
263
293
|
# Unique indexes can be identified by columns or name:
|
264
294
|
#
|
@@ -425,6 +455,62 @@ module ActiveRecord
|
|
425
455
|
end
|
426
456
|
end
|
427
457
|
|
458
|
+
# Accepts a list of attribute names to be used in the WHERE clause
|
459
|
+
# of SELECT / UPDATE / DELETE queries and in the ORDER BY clause for `#first` and `#last` finder methods.
|
460
|
+
#
|
461
|
+
# class Developer < ActiveRecord::Base
|
462
|
+
# query_constraints :company_id, :id
|
463
|
+
# end
|
464
|
+
#
|
465
|
+
# developer = Developer.first
|
466
|
+
# # SELECT "developers".* FROM "developers" ORDER BY "developers"."company_id" ASC, "developers"."id" ASC LIMIT 1
|
467
|
+
# developer.inspect # => #<Developer id: 1, company_id: 1, ...>
|
468
|
+
#
|
469
|
+
# developer.update!(name: "Nikita")
|
470
|
+
# # UPDATE "developers" SET "name" = 'Nikita' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
471
|
+
#
|
472
|
+
# It is possible to update attribute used in the query_by clause:
|
473
|
+
# developer.update!(company_id: 2)
|
474
|
+
# # UPDATE "developers" SET "company_id" = 2 WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
475
|
+
#
|
476
|
+
# developer.name = "Bob"
|
477
|
+
# developer.save!
|
478
|
+
# # UPDATE "developers" SET "name" = 'Bob' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
479
|
+
#
|
480
|
+
# developer.destroy!
|
481
|
+
# # DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
482
|
+
#
|
483
|
+
# developer.delete
|
484
|
+
# # DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
|
485
|
+
#
|
486
|
+
# developer.reload
|
487
|
+
# # SELECT "developers".* FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1 LIMIT 1
|
488
|
+
def query_constraints(*columns_list)
|
489
|
+
raise ArgumentError, "You must specify at least one column to be used in querying" if columns_list.empty?
|
490
|
+
|
491
|
+
@query_constraints_list = columns_list.map(&:to_s)
|
492
|
+
@has_query_constraints = @query_constraints_list
|
493
|
+
end
|
494
|
+
|
495
|
+
def has_query_constraints? # :nodoc:
|
496
|
+
@has_query_constraints
|
497
|
+
end
|
498
|
+
|
499
|
+
def query_constraints_list # :nodoc:
|
500
|
+
@query_constraints_list ||= if base_class? || primary_key != base_class.primary_key
|
501
|
+
primary_key if primary_key.is_a?(Array)
|
502
|
+
else
|
503
|
+
base_class.query_constraints_list
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
# Returns an array of column names to be used in queries. The source of column
|
508
|
+
# names is derived from +query_constraints_list+ or +primary_key+. This method
|
509
|
+
# is for internal use when the primary key is to be treated as an array.
|
510
|
+
def composite_query_constraints_list # :nodoc:
|
511
|
+
@composite_query_constraints_list ||= query_constraints_list || Array(primary_key)
|
512
|
+
end
|
513
|
+
|
428
514
|
# Destroy an object (or multiple objects) that has the given id. The object is instantiated first,
|
429
515
|
# therefore all callbacks and filters are fired off before the object is deleted. This method is
|
430
516
|
# less efficient than #delete but allows cleanup methods and other actions to be run.
|
@@ -445,7 +531,13 @@ module ActiveRecord
|
|
445
531
|
# todos = [1,2,3]
|
446
532
|
# Todo.destroy(todos)
|
447
533
|
def destroy(id)
|
448
|
-
if
|
534
|
+
multiple_ids = if composite_primary_key?
|
535
|
+
id.first.is_a?(Array)
|
536
|
+
else
|
537
|
+
id.is_a?(Array)
|
538
|
+
end
|
539
|
+
|
540
|
+
if multiple_ids
|
449
541
|
find(id).each(&:destroy)
|
450
542
|
else
|
451
543
|
find(id).destroy
|
@@ -474,7 +566,7 @@ module ActiveRecord
|
|
474
566
|
delete_by(primary_key => id_or_array)
|
475
567
|
end
|
476
568
|
|
477
|
-
def _insert_record(values) # :nodoc:
|
569
|
+
def _insert_record(values, returning) # :nodoc:
|
478
570
|
primary_key = self.primary_key
|
479
571
|
primary_key_value = nil
|
480
572
|
|
@@ -493,7 +585,10 @@ module ActiveRecord
|
|
493
585
|
im.insert(values.transform_keys { |name| arel_table[name] })
|
494
586
|
end
|
495
587
|
|
496
|
-
connection.insert(
|
588
|
+
connection.insert(
|
589
|
+
im, "#{self} Create", primary_key || false, primary_key_value,
|
590
|
+
returning: returning
|
591
|
+
)
|
497
592
|
end
|
498
593
|
|
499
594
|
def _update_record(values, constraints) # :nodoc:
|
@@ -530,6 +625,14 @@ module ActiveRecord
|
|
530
625
|
end
|
531
626
|
|
532
627
|
private
|
628
|
+
def inherited(subclass)
|
629
|
+
super
|
630
|
+
subclass.class_eval do
|
631
|
+
@_query_constraints_list = nil
|
632
|
+
@has_query_constraints = false
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
533
636
|
# Given a class, an attributes hash, +instantiate_instance_of+ returns a
|
534
637
|
# new instance of the class. Accepts only keys as strings.
|
535
638
|
def instantiate_instance_of(klass, attributes, column_types = {}, &block)
|
@@ -564,7 +667,7 @@ module ActiveRecord
|
|
564
667
|
end
|
565
668
|
|
566
669
|
# Returns true if this object was just created -- that is, prior to the last
|
567
|
-
#
|
670
|
+
# update or delete, the object didn't exist in the database and new_record? would have
|
568
671
|
# returned true.
|
569
672
|
def previously_new_record?
|
570
673
|
@previously_new_record
|
@@ -663,6 +766,7 @@ module ActiveRecord
|
|
663
766
|
def delete
|
664
767
|
_delete_row if persisted?
|
665
768
|
@destroyed = true
|
769
|
+
@previously_new_record = false
|
666
770
|
freeze
|
667
771
|
end
|
668
772
|
|
@@ -676,12 +780,9 @@ module ActiveRecord
|
|
676
780
|
def destroy
|
677
781
|
_raise_readonly_record_error if readonly?
|
678
782
|
destroy_associations
|
679
|
-
@_trigger_destroy_callback
|
680
|
-
destroy_row > 0
|
681
|
-
else
|
682
|
-
true
|
683
|
-
end
|
783
|
+
@_trigger_destroy_callback ||= persisted? && destroy_row > 0
|
684
784
|
@destroyed = true
|
785
|
+
@previously_new_record = false
|
685
786
|
freeze
|
686
787
|
end
|
687
788
|
|
@@ -707,11 +808,14 @@ module ActiveRecord
|
|
707
808
|
# Note: The new instance will share a link to the same attributes as the original class.
|
708
809
|
# Therefore the STI column value will still be the same.
|
709
810
|
# Any change to the attributes on either instance will affect both instances.
|
811
|
+
# This includes any attribute initialization done by the new instance.
|
812
|
+
#
|
710
813
|
# If you want to change the STI column as well, use #becomes! instead.
|
711
814
|
def becomes(klass)
|
712
815
|
became = klass.allocate
|
713
816
|
|
714
817
|
became.send(:initialize) do |becoming|
|
818
|
+
@attributes.reverse_merge!(becoming.instance_variable_get(:@attributes))
|
715
819
|
becoming.instance_variable_set(:@attributes, @attributes)
|
716
820
|
becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil)
|
717
821
|
becoming.instance_variable_set(:@new_record, new_record?)
|
@@ -746,7 +850,7 @@ module ActiveRecord
|
|
746
850
|
# * updated_at/updated_on column is updated if that column is available.
|
747
851
|
# * Updates all the attributes that are dirty in this object.
|
748
852
|
#
|
749
|
-
# This method raises an ActiveRecord::ActiveRecordError
|
853
|
+
# This method raises an ActiveRecord::ActiveRecordError if the
|
750
854
|
# attribute is marked as readonly.
|
751
855
|
#
|
752
856
|
# Also see #update_column.
|
@@ -758,6 +862,28 @@ module ActiveRecord
|
|
758
862
|
save(validate: false)
|
759
863
|
end
|
760
864
|
|
865
|
+
# Updates a single attribute and saves the record.
|
866
|
+
# This is especially useful for boolean flags on existing records. Also note that
|
867
|
+
#
|
868
|
+
# * Validation is skipped.
|
869
|
+
# * \Callbacks are invoked.
|
870
|
+
# * updated_at/updated_on column is updated if that column is available.
|
871
|
+
# * Updates all the attributes that are dirty in this object.
|
872
|
+
#
|
873
|
+
# This method raises an ActiveRecord::ActiveRecordError if the
|
874
|
+
# attribute is marked as readonly.
|
875
|
+
#
|
876
|
+
# If any of the <tt>before_*</tt> callbacks throws +:abort+ the action is cancelled
|
877
|
+
# and #update_attribute! raises ActiveRecord::RecordNotSaved. See
|
878
|
+
# ActiveRecord::Callbacks for further details.
|
879
|
+
def update_attribute!(name, value)
|
880
|
+
name = name.to_s
|
881
|
+
verify_readonly_attribute(name)
|
882
|
+
public_send("#{name}=", value)
|
883
|
+
|
884
|
+
save!(validate: false)
|
885
|
+
end
|
886
|
+
|
761
887
|
# Updates the attributes of the model from the passed-in hash and saves the
|
762
888
|
# record, all wrapped in a transaction. If the object is invalid, the saving
|
763
889
|
# will fail and false will be returned.
|
@@ -944,7 +1070,7 @@ module ActiveRecord
|
|
944
1070
|
self.class.connection.clear_query_cache
|
945
1071
|
|
946
1072
|
fresh_object = if apply_scoping?(options)
|
947
|
-
_find_record(options)
|
1073
|
+
_find_record((options || {}).merge(all_queries: true))
|
948
1074
|
else
|
949
1075
|
self.class.unscoped { _find_record(options) }
|
950
1076
|
end
|
@@ -995,10 +1121,12 @@ module ActiveRecord
|
|
995
1121
|
_raise_readonly_record_error if readonly?
|
996
1122
|
|
997
1123
|
attribute_names = timestamp_attributes_for_update_in_model
|
998
|
-
attribute_names
|
1124
|
+
attribute_names = (attribute_names | names).map! do |name|
|
999
1125
|
name = name.to_s
|
1000
|
-
self.class.attribute_aliases[name] || name
|
1001
|
-
|
1126
|
+
name = self.class.attribute_aliases[name] || name
|
1127
|
+
verify_readonly_attribute(name)
|
1128
|
+
name
|
1129
|
+
end
|
1002
1130
|
|
1003
1131
|
unless attribute_names.empty?
|
1004
1132
|
affected_rows = _touch_row(attribute_names, time)
|
@@ -1009,6 +1137,12 @@ module ActiveRecord
|
|
1009
1137
|
end
|
1010
1138
|
|
1011
1139
|
private
|
1140
|
+
def init_internals
|
1141
|
+
super
|
1142
|
+
@_trigger_destroy_callback = @_trigger_update_callback = nil
|
1143
|
+
@previously_new_record = false
|
1144
|
+
end
|
1145
|
+
|
1012
1146
|
def strict_loaded_associations
|
1013
1147
|
@association_cache.find_all do |_, assoc|
|
1014
1148
|
assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
|
@@ -1016,10 +1150,23 @@ module ActiveRecord
|
|
1016
1150
|
end
|
1017
1151
|
|
1018
1152
|
def _find_record(options)
|
1153
|
+
all_queries = options ? options[:all_queries] : nil
|
1154
|
+
base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
|
1155
|
+
|
1019
1156
|
if options && options[:lock]
|
1020
|
-
|
1157
|
+
base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
|
1021
1158
|
else
|
1022
|
-
|
1159
|
+
base.find_by!(_in_memory_query_constraints_hash)
|
1160
|
+
end
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
def _in_memory_query_constraints_hash
|
1164
|
+
if self.class.query_constraints_list.nil?
|
1165
|
+
{ @primary_key => id }
|
1166
|
+
else
|
1167
|
+
self.class.query_constraints_list.index_with do |column_name|
|
1168
|
+
attribute(column_name)
|
1169
|
+
end
|
1023
1170
|
end
|
1024
1171
|
end
|
1025
1172
|
|
@@ -1029,7 +1176,13 @@ module ActiveRecord
|
|
1029
1176
|
end
|
1030
1177
|
|
1031
1178
|
def _query_constraints_hash
|
1032
|
-
|
1179
|
+
if self.class.query_constraints_list.nil?
|
1180
|
+
{ @primary_key => id_in_database }
|
1181
|
+
else
|
1182
|
+
self.class.query_constraints_list.index_with do |column_name|
|
1183
|
+
attribute_in_database(column_name)
|
1184
|
+
end
|
1185
|
+
end
|
1033
1186
|
end
|
1034
1187
|
|
1035
1188
|
# A hook to be overridden by association modules.
|
@@ -1093,11 +1246,16 @@ module ActiveRecord
|
|
1093
1246
|
def _create_record(attribute_names = self.attribute_names)
|
1094
1247
|
attribute_names = attributes_for_create(attribute_names)
|
1095
1248
|
|
1096
|
-
|
1097
|
-
|
1249
|
+
returning_columns = self.class._returning_columns_for_insert
|
1250
|
+
|
1251
|
+
returning_values = self.class._insert_record(
|
1252
|
+
attributes_with_values(attribute_names),
|
1253
|
+
returning_columns
|
1098
1254
|
)
|
1099
1255
|
|
1100
|
-
|
1256
|
+
returning_columns.zip(returning_values).each do |column, value|
|
1257
|
+
_write_attribute(column, value) if !_read_attribute(column)
|
1258
|
+
end if returning_values
|
1101
1259
|
|
1102
1260
|
@new_record = false
|
1103
1261
|
@previously_new_record = true
|
@@ -1114,7 +1272,7 @@ module ActiveRecord
|
|
1114
1272
|
def _raise_record_not_destroyed
|
1115
1273
|
@_association_destroy_exception ||= nil
|
1116
1274
|
key = self.class.primary_key
|
1117
|
-
raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{
|
1275
|
+
raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
|
1118
1276
|
ensure
|
1119
1277
|
@_association_destroy_exception = nil
|
1120
1278
|
end
|
@@ -1129,11 +1287,5 @@ module ActiveRecord
|
|
1129
1287
|
persisted?, new_record?, or destroyed? before touching.
|
1130
1288
|
MSG
|
1131
1289
|
end
|
1132
|
-
|
1133
|
-
# The name of the method used to touch a +belongs_to+ association when the
|
1134
|
-
# +:touch+ option is used.
|
1135
|
-
def belongs_to_touch_method
|
1136
|
-
:touch
|
1137
|
-
end
|
1138
1290
|
end
|
1139
1291
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class Promise < BasicObject
|
5
|
+
undef_method :==, :!, :!=
|
6
|
+
|
7
|
+
def initialize(future_result, block) # :nodoc:
|
8
|
+
@future_result = future_result
|
9
|
+
@block = block
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns whether the associated query is still being executed or not.
|
13
|
+
def pending?
|
14
|
+
@future_result.pending?
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the query result.
|
18
|
+
# If the query wasn't completed yet, accessing +#value+ will block until the query completes.
|
19
|
+
# If the query failed, +#value+ will raise the corresponding error.
|
20
|
+
def value
|
21
|
+
return @value if defined? @value
|
22
|
+
|
23
|
+
result = @future_result.result
|
24
|
+
@value = if @block
|
25
|
+
@block.call(result)
|
26
|
+
else
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns a new +ActiveRecord::Promise+ that will apply the passed block
|
32
|
+
# when the value is accessed:
|
33
|
+
#
|
34
|
+
# Post.async_pluck(:title).then { |title| title.upcase }.value
|
35
|
+
# # => "POST TITLE"
|
36
|
+
def then(&block)
|
37
|
+
Promise.new(@future_result, @block ? @block >> block : block)
|
38
|
+
end
|
39
|
+
|
40
|
+
[:class, :respond_to?, :is_a?].each do |method|
|
41
|
+
define_method(method, ::Object.instance_method(method))
|
42
|
+
end
|
43
|
+
|
44
|
+
def inspect # :nodoc:
|
45
|
+
"#<ActiveRecord::Promise status=#{status}>"
|
46
|
+
end
|
47
|
+
|
48
|
+
def pretty_print(q) # :nodoc:
|
49
|
+
q.text(inspect)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def status
|
54
|
+
if @future_result.pending?
|
55
|
+
:pending
|
56
|
+
elsif @future_result.canceled?
|
57
|
+
:canceled
|
58
|
+
else
|
59
|
+
:complete
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Complete < self # :nodoc:
|
64
|
+
attr_reader :value
|
65
|
+
|
66
|
+
def initialize(value)
|
67
|
+
@value = value
|
68
|
+
end
|
69
|
+
|
70
|
+
def then
|
71
|
+
Complete.new(yield @value)
|
72
|
+
end
|
73
|
+
|
74
|
+
def pending?
|
75
|
+
false
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def status
|
80
|
+
:complete
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -26,32 +26,14 @@ module ActiveRecord
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.run
|
29
|
-
|
30
|
-
|
31
|
-
if ActiveRecord.legacy_connection_handling
|
32
|
-
ActiveRecord::Base.connection_handlers.each do |key, handler|
|
33
|
-
pools.concat(handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
|
34
|
-
end
|
35
|
-
else
|
36
|
-
pools.concat(ActiveRecord::Base.connection_handler.all_connection_pools.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
|
37
|
-
end
|
38
|
-
|
39
|
-
pools
|
29
|
+
ActiveRecord::Base.connection_handler.each_connection_pool.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
|
40
30
|
end
|
41
31
|
|
42
32
|
def self.complete(pools)
|
43
33
|
pools.each { |pool| pool.disable_query_cache! }
|
44
34
|
|
45
|
-
|
46
|
-
|
47
|
-
handler.connection_pool_list.each do |pool|
|
48
|
-
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
|
49
|
-
end
|
50
|
-
end
|
51
|
-
else
|
52
|
-
ActiveRecord::Base.connection_handler.all_connection_pools.each do |pool|
|
53
|
-
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
|
54
|
-
end
|
35
|
+
ActiveRecord::Base.connection_handler.each_connection_pool do |pool|
|
36
|
+
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
|
55
37
|
end
|
56
38
|
end
|
57
39
|
|