activerecord 7.0.5 → 7.1.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1624 -1338
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +16 -13
- data/lib/active_record/association_relation.rb +1 -1
- data/lib/active_record/associations/association.rb +20 -4
- 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 +31 -7
- 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 +313 -217
- 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 +52 -34
- 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 +55 -9
- 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 +74 -51
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +129 -31
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +62 -23
- 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 +290 -125
- data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
- data/lib/active_record/connection_adapters/abstract_adapter.rb +505 -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 +151 -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 +75 -41
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- 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 +2 -2
- 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 +361 -60
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +353 -192
- 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 +52 -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 +211 -83
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +262 -0
- data/lib/active_record/connection_adapters.rb +3 -1
- data/lib/active_record/connection_handling.rb +72 -95
- data/lib/active_record/core.rb +175 -153
- 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 +9 -4
- 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 +42 -18
- data/lib/active_record/encryption/encrypted_attribute_type.rb +21 -6
- data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
- 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 +112 -28
- data/lib/active_record/errors.rb +112 -18
- 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 +135 -71
- data/lib/active_record/future_result.rb +31 -5
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +30 -16
- data/lib/active_record/insert_all.rb +57 -10
- data/lib/active_record/integration.rb +8 -8
- data/lib/active_record/internal_metadata.rb +120 -30
- data/lib/active_record/locking/optimistic.rb +32 -18
- 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 +6 -8
- 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 +150 -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/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +271 -114
- data/lib/active_record/model_schema.rb +64 -44
- data/lib/active_record/nested_attributes.rb +24 -6
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +195 -42
- 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 +14 -9
- data/lib/active_record/railties/databases.rake +142 -148
- 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 +182 -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 +187 -63
- data/lib/active_record/relation/delegation.rb +23 -9
- 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 +31 -3
- 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 +386 -70
- data/lib/active_record/relation/spawn_methods.rb +18 -1
- data/lib/active_record/relation.rb +91 -35
- data/lib/active_record/result.rb +25 -9
- data/lib/active_record/runtime_registry.rb +24 -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 +16 -3
- 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 +1 -9
- 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 +51 -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
|
@@ -85,14 +115,14 @@ module ActiveRecord
|
|
85
115
|
# ==== Options
|
86
116
|
#
|
87
117
|
# [:returning]
|
88
|
-
# (PostgreSQL only) An array of attributes to return for all successfully
|
118
|
+
# (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
|
89
119
|
# inserted records, which by default is the primary key.
|
90
120
|
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
91
121
|
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
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.
|
@@ -175,14 +205,14 @@ module ActiveRecord
|
|
175
205
|
# ==== Options
|
176
206
|
#
|
177
207
|
# [:returning]
|
178
|
-
# (PostgreSQL only) An array of attributes to return for all successfully
|
208
|
+
# (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
|
179
209
|
# inserted records, which by default is the primary key.
|
180
210
|
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
181
211
|
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
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
|
@@ -241,14 +271,14 @@ module ActiveRecord
|
|
241
271
|
# ==== Options
|
242
272
|
#
|
243
273
|
# [:returning]
|
244
|
-
# (PostgreSQL only) An array of attributes to return for all successfully
|
274
|
+
# (PostgreSQL and SQLite3 only) An array of attributes to return for all successfully
|
245
275
|
# inserted records, which by default is the primary key.
|
246
276
|
# Pass <tt>returning: %w[ id name ]</tt> for both id and name
|
247
277
|
# or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
|
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.
|
@@ -813,7 +939,7 @@ module ActiveRecord
|
|
813
939
|
verify_readonly_attribute(name) || name
|
814
940
|
end
|
815
941
|
|
816
|
-
update_constraints =
|
942
|
+
update_constraints = _query_constraints_hash
|
817
943
|
attributes = attributes.each_with_object({}) do |(k, v), h|
|
818
944
|
h[k] = @attributes.write_cast_value(k, v)
|
819
945
|
clear_attribute_change(k)
|
@@ -944,12 +1070,13 @@ 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
|
951
1077
|
|
952
1078
|
@association_cache = fresh_object.instance_variable_get(:@association_cache)
|
1079
|
+
@association_cache.each_value { |association| association.owner = self }
|
953
1080
|
@attributes = fresh_object.instance_variable_get(:@attributes)
|
954
1081
|
@new_record = false
|
955
1082
|
@previously_new_record = false
|
@@ -995,10 +1122,12 @@ module ActiveRecord
|
|
995
1122
|
_raise_readonly_record_error if readonly?
|
996
1123
|
|
997
1124
|
attribute_names = timestamp_attributes_for_update_in_model
|
998
|
-
attribute_names
|
1125
|
+
attribute_names = (attribute_names | names).map! do |name|
|
999
1126
|
name = name.to_s
|
1000
|
-
self.class.attribute_aliases[name] || name
|
1001
|
-
|
1127
|
+
name = self.class.attribute_aliases[name] || name
|
1128
|
+
verify_readonly_attribute(name)
|
1129
|
+
name
|
1130
|
+
end
|
1002
1131
|
|
1003
1132
|
unless attribute_names.empty?
|
1004
1133
|
affected_rows = _touch_row(attribute_names, time)
|
@@ -1009,6 +1138,12 @@ module ActiveRecord
|
|
1009
1138
|
end
|
1010
1139
|
|
1011
1140
|
private
|
1141
|
+
def init_internals
|
1142
|
+
super
|
1143
|
+
@_trigger_destroy_callback = @_trigger_update_callback = nil
|
1144
|
+
@previously_new_record = false
|
1145
|
+
end
|
1146
|
+
|
1012
1147
|
def strict_loaded_associations
|
1013
1148
|
@association_cache.find_all do |_, assoc|
|
1014
1149
|
assoc.owner.strict_loading? && !assoc.owner.strict_loading_n_plus_one_only?
|
@@ -1016,10 +1151,23 @@ module ActiveRecord
|
|
1016
1151
|
end
|
1017
1152
|
|
1018
1153
|
def _find_record(options)
|
1154
|
+
all_queries = options ? options[:all_queries] : nil
|
1155
|
+
base = self.class.all(all_queries: all_queries).preload(strict_loaded_associations)
|
1156
|
+
|
1019
1157
|
if options && options[:lock]
|
1020
|
-
|
1158
|
+
base.lock(options[:lock]).find_by!(_in_memory_query_constraints_hash)
|
1021
1159
|
else
|
1022
|
-
|
1160
|
+
base.find_by!(_in_memory_query_constraints_hash)
|
1161
|
+
end
|
1162
|
+
end
|
1163
|
+
|
1164
|
+
def _in_memory_query_constraints_hash
|
1165
|
+
if self.class.query_constraints_list.nil?
|
1166
|
+
{ @primary_key => id }
|
1167
|
+
else
|
1168
|
+
self.class.query_constraints_list.index_with do |column_name|
|
1169
|
+
attribute(column_name)
|
1170
|
+
end
|
1023
1171
|
end
|
1024
1172
|
end
|
1025
1173
|
|
@@ -1028,8 +1176,14 @@ module ActiveRecord
|
|
1028
1176
|
(self.class.default_scopes?(all_queries: true) || self.class.global_current_scope)
|
1029
1177
|
end
|
1030
1178
|
|
1031
|
-
def
|
1032
|
-
|
1179
|
+
def _query_constraints_hash
|
1180
|
+
if self.class.query_constraints_list.nil?
|
1181
|
+
{ @primary_key => id_in_database }
|
1182
|
+
else
|
1183
|
+
self.class.query_constraints_list.index_with do |column_name|
|
1184
|
+
attribute_in_database(column_name)
|
1185
|
+
end
|
1186
|
+
end
|
1033
1187
|
end
|
1034
1188
|
|
1035
1189
|
# A hook to be overridden by association modules.
|
@@ -1041,7 +1195,7 @@ module ActiveRecord
|
|
1041
1195
|
end
|
1042
1196
|
|
1043
1197
|
def _delete_row
|
1044
|
-
self.class._delete_record(
|
1198
|
+
self.class._delete_record(_query_constraints_hash)
|
1045
1199
|
end
|
1046
1200
|
|
1047
1201
|
def _touch_row(attribute_names, time)
|
@@ -1057,7 +1211,7 @@ module ActiveRecord
|
|
1057
1211
|
def _update_row(attribute_names, attempted_action = "update")
|
1058
1212
|
self.class._update_record(
|
1059
1213
|
attributes_with_values(attribute_names),
|
1060
|
-
|
1214
|
+
_query_constraints_hash
|
1061
1215
|
)
|
1062
1216
|
end
|
1063
1217
|
|
@@ -1093,11 +1247,16 @@ module ActiveRecord
|
|
1093
1247
|
def _create_record(attribute_names = self.attribute_names)
|
1094
1248
|
attribute_names = attributes_for_create(attribute_names)
|
1095
1249
|
|
1096
|
-
|
1097
|
-
|
1250
|
+
returning_columns = self.class._returning_columns_for_insert
|
1251
|
+
|
1252
|
+
returning_values = self.class._insert_record(
|
1253
|
+
attributes_with_values(attribute_names),
|
1254
|
+
returning_columns
|
1098
1255
|
)
|
1099
1256
|
|
1100
|
-
|
1257
|
+
returning_columns.zip(returning_values).each do |column, value|
|
1258
|
+
_write_attribute(column, value) if !_read_attribute(column)
|
1259
|
+
end if returning_values
|
1101
1260
|
|
1102
1261
|
@new_record = false
|
1103
1262
|
@previously_new_record = true
|
@@ -1114,7 +1273,7 @@ module ActiveRecord
|
|
1114
1273
|
def _raise_record_not_destroyed
|
1115
1274
|
@_association_destroy_exception ||= nil
|
1116
1275
|
key = self.class.primary_key
|
1117
|
-
raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{
|
1276
|
+
raise @_association_destroy_exception || RecordNotDestroyed.new("Failed to destroy #{self.class} with #{key}=#{id}", self)
|
1118
1277
|
ensure
|
1119
1278
|
@_association_destroy_exception = nil
|
1120
1279
|
end
|
@@ -1129,11 +1288,5 @@ module ActiveRecord
|
|
1129
1288
|
persisted?, new_record?, or destroyed? before touching.
|
1130
1289
|
MSG
|
1131
1290
|
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
1291
|
end
|
1139
1292
|
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_pick(: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
|
|