activerecord 6.1.6 → 7.0.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1314 -975
- data/README.rdoc +1 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/association_relation.rb +0 -10
- data/lib/active_record/associations/association.rb +33 -17
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +15 -4
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +8 -2
- data/lib/active_record/associations/builder/belongs_to.rb +19 -6
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_many.rb +3 -2
- data/lib/active_record/associations/builder/has_one.rb +2 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -2
- data/lib/active_record/associations/collection_association.rb +19 -21
- data/lib/active_record/associations/collection_proxy.rb +10 -5
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +8 -5
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/associations/has_one_association.rb +10 -7
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +23 -15
- data/lib/active_record/associations/preloader/association.rb +186 -52
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +49 -13
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +124 -95
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -1
- data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
- data/lib/active_record/attribute_methods/dirty.rb +49 -16
- data/lib/active_record/attribute_methods/primary_key.rb +2 -2
- data/lib/active_record/attribute_methods/query.rb +2 -2
- data/lib/active_record/attribute_methods/read.rb +7 -5
- data/lib/active_record/attribute_methods/serialization.rb +57 -19
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +14 -15
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +8 -23
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +10 -2
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +38 -13
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +80 -24
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +105 -81
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -24
- data/lib/active_record/connection_adapters/mysql/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +7 -7
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +51 -51
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +37 -19
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +208 -107
- data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +17 -15
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +96 -32
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +49 -55
- data/lib/active_record/core.rb +124 -134
- data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
- data/lib/active_record/database_configurations/database_config.rb +12 -9
- data/lib/active_record/database_configurations/hash_config.rb +63 -5
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +15 -32
- data/lib/active_record/delegated_type.rb +53 -12
- data/lib/active_record/destroy_association_async_job.rb +1 -1
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +1 -1
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +44 -0
- data/lib/active_record/encryption/configurable.rb +67 -0
- data/lib/active_record/encryption/context.rb +35 -0
- data/lib/active_record/encryption/contexts.rb +72 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +206 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +155 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +42 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_serializer.rb +90 -0
- data/lib/active_record/encryption/null_encryptor.rb +21 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
- data/lib/active_record/encryption/scheme.rb +99 -0
- data/lib/active_record/encryption.rb +55 -0
- data/lib/active_record/enum.rb +50 -43
- data/lib/active_record/errors.rb +67 -4
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +41 -6
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +20 -23
- data/lib/active_record/future_result.rb +139 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +55 -17
- data/lib/active_record/insert_all.rb +80 -14
- data/lib/active_record/integration.rb +4 -3
- data/lib/active_record/internal_metadata.rb +1 -5
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/locking/pessimistic.rb +10 -4
- data/lib/active_record/log_subscriber.rb +23 -7
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +18 -6
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +7 -7
- data/lib/active_record/migration/compatibility.rb +84 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +114 -83
- data/lib/active_record/model_schema.rb +58 -59
- data/lib/active_record/nested_attributes.rb +13 -12
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +228 -60
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +16 -6
- data/lib/active_record/railtie.rb +136 -22
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +78 -136
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +73 -50
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +6 -6
- data/lib/active_record/relation/calculations.rb +43 -38
- data/lib/active_record/relation/delegation.rb +7 -7
- data/lib/active_record/relation/finder_methods.rb +31 -35
- data/lib/active_record/relation/merger.rb +20 -13
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +276 -67
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +189 -88
- data/lib/active_record/result.rb +17 -7
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +17 -12
- data/lib/active_record/schema.rb +38 -23
- data/lib/active_record/schema_dumper.rb +25 -19
- data/lib/active_record/schema_migration.rb +4 -4
- data/lib/active_record/scoping/default.rb +60 -13
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +3 -3
- data/lib/active_record/store.rb +7 -2
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +127 -60
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +16 -9
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -7
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +2 -2
- data/lib/active_record/type/serialized.rb +1 -1
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/associated.rb +4 -4
- data/lib/active_record/validations/presence.rb +2 -2
- data/lib/active_record/validations/uniqueness.rb +4 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +217 -27
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +1 -0
- data/lib/arel/predications.rb +11 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +0 -1
- data/lib/arel/tree_manager.rb +0 -12
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +8 -2
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +58 -2
- data/lib/arel.rb +2 -1
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +55 -11
@@ -8,14 +8,12 @@ require "active_support/core_ext/array/wrap"
|
|
8
8
|
|
9
9
|
module ActiveRecord
|
10
10
|
module QueryMethods
|
11
|
-
extend ActiveSupport::Concern
|
12
|
-
|
13
11
|
include ActiveModel::ForbiddenAttributesProtection
|
14
12
|
|
15
|
-
# WhereChain objects act as placeholder for queries in which
|
16
|
-
# In this case,
|
13
|
+
# WhereChain objects act as placeholder for queries in which +where+ does not have any parameter.
|
14
|
+
# In this case, +where+ can be chained to return a new relation.
|
17
15
|
class WhereChain
|
18
|
-
def initialize(scope)
|
16
|
+
def initialize(scope) # :nodoc:
|
19
17
|
@scope = scope
|
20
18
|
end
|
21
19
|
|
@@ -42,6 +40,13 @@ module ActiveRecord
|
|
42
40
|
#
|
43
41
|
# User.where.not(name: "Jon", role: "admin")
|
44
42
|
# # SELECT * FROM users WHERE NOT (name == 'Jon' AND role == 'admin')
|
43
|
+
#
|
44
|
+
# If there is a non-nil condition on a nullable column in the hash condition, the records that have
|
45
|
+
# nil values on the nullable column won't be returned.
|
46
|
+
# User.create!(nullable_country: nil)
|
47
|
+
# User.where.not(nullable_country: "UK")
|
48
|
+
# # SELECT * FROM users WHERE NOT (nullable_country = 'UK')
|
49
|
+
# # => []
|
45
50
|
def not(opts, *rest)
|
46
51
|
where_clause = @scope.send(:build_where_clause, opts, rest)
|
47
52
|
|
@@ -50,6 +55,34 @@ module ActiveRecord
|
|
50
55
|
@scope
|
51
56
|
end
|
52
57
|
|
58
|
+
# Returns a new relation with joins and where clause to identify
|
59
|
+
# associated relations.
|
60
|
+
#
|
61
|
+
# For example, posts that are associated to a related author:
|
62
|
+
#
|
63
|
+
# Post.where.associated(:author)
|
64
|
+
# # SELECT "posts".* FROM "posts"
|
65
|
+
# # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
66
|
+
# # WHERE "authors"."id" IS NOT NULL
|
67
|
+
#
|
68
|
+
# Additionally, multiple relations can be combined. This will return posts
|
69
|
+
# associated to both an author and any comments:
|
70
|
+
#
|
71
|
+
# Post.where.associated(:author, :comments)
|
72
|
+
# # SELECT "posts".* FROM "posts"
|
73
|
+
# # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
74
|
+
# # INNER JOIN "comments" ON "comments"."post_id" = "posts"."id"
|
75
|
+
# # WHERE "authors"."id" IS NOT NULL AND "comments"."id" IS NOT NULL
|
76
|
+
def associated(*associations)
|
77
|
+
associations.each do |association|
|
78
|
+
reflection = scope_association_reflection(association)
|
79
|
+
@scope.joins!(association)
|
80
|
+
self.not(reflection.table_name => { reflection.association_primary_key => nil })
|
81
|
+
end
|
82
|
+
|
83
|
+
@scope
|
84
|
+
end
|
85
|
+
|
53
86
|
# Returns a new relation with left outer joins and where clause to identify
|
54
87
|
# missing relations.
|
55
88
|
#
|
@@ -68,16 +101,24 @@ module ActiveRecord
|
|
68
101
|
# # LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
69
102
|
# # LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id"
|
70
103
|
# # WHERE "authors"."id" IS NULL AND "comments"."id" IS NULL
|
71
|
-
def missing(*
|
72
|
-
|
73
|
-
reflection =
|
74
|
-
|
75
|
-
@scope.
|
76
|
-
@scope.where!(opts)
|
104
|
+
def missing(*associations)
|
105
|
+
associations.each do |association|
|
106
|
+
reflection = scope_association_reflection(association)
|
107
|
+
@scope.left_outer_joins!(association)
|
108
|
+
@scope.where!(reflection.table_name => { reflection.association_primary_key => nil })
|
77
109
|
end
|
78
110
|
|
79
111
|
@scope
|
80
112
|
end
|
113
|
+
|
114
|
+
private
|
115
|
+
def scope_association_reflection(association)
|
116
|
+
reflection = @scope.klass._reflect_on_association(association)
|
117
|
+
unless reflection
|
118
|
+
raise ArgumentError.new("An association named `:#{association}` does not exist on the model `#{@scope.name}`.")
|
119
|
+
end
|
120
|
+
reflection
|
121
|
+
end
|
81
122
|
end
|
82
123
|
|
83
124
|
FROZEN_EMPTY_ARRAY = [].freeze
|
@@ -128,7 +169,7 @@ module ActiveRecord
|
|
128
169
|
#
|
129
170
|
# users = User.includes(:address, friends: [:address, :followers])
|
130
171
|
#
|
131
|
-
# ===
|
172
|
+
# === Conditions
|
132
173
|
#
|
133
174
|
# If you want to add string conditions to your included models, you'll have
|
134
175
|
# to explicitly reference them. For example:
|
@@ -148,7 +189,7 @@ module ActiveRecord
|
|
148
189
|
#
|
149
190
|
# User.includes(:posts).where(posts: { name: 'example' })
|
150
191
|
def includes(*args)
|
151
|
-
check_if_method_has_arguments!(
|
192
|
+
check_if_method_has_arguments!(__callee__, args)
|
152
193
|
spawn.includes!(*args)
|
153
194
|
end
|
154
195
|
|
@@ -164,7 +205,7 @@ module ActiveRecord
|
|
164
205
|
# # FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" =
|
165
206
|
# # "users"."id"
|
166
207
|
def eager_load(*args)
|
167
|
-
check_if_method_has_arguments!(
|
208
|
+
check_if_method_has_arguments!(__callee__, args)
|
168
209
|
spawn.eager_load!(*args)
|
169
210
|
end
|
170
211
|
|
@@ -178,7 +219,7 @@ module ActiveRecord
|
|
178
219
|
# User.preload(:posts)
|
179
220
|
# # SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1, 2, 3)
|
180
221
|
def preload(*args)
|
181
|
-
check_if_method_has_arguments!(
|
222
|
+
check_if_method_has_arguments!(__callee__, args)
|
182
223
|
spawn.preload!(*args)
|
183
224
|
end
|
184
225
|
|
@@ -211,7 +252,7 @@ module ActiveRecord
|
|
211
252
|
# User.includes(:posts).where("posts.name = 'foo'").references(:posts)
|
212
253
|
# # Query now knows the string references posts, so adds a JOIN
|
213
254
|
def references(*table_names)
|
214
|
-
check_if_method_has_arguments!(
|
255
|
+
check_if_method_has_arguments!(__callee__, table_names)
|
215
256
|
spawn.references!(*table_names)
|
216
257
|
end
|
217
258
|
|
@@ -269,7 +310,7 @@ module ActiveRecord
|
|
269
310
|
return super()
|
270
311
|
end
|
271
312
|
|
272
|
-
check_if_method_has_arguments!(
|
313
|
+
check_if_method_has_arguments!(__callee__, fields, "Call `select' with at least one field.")
|
273
314
|
spawn._select!(*fields)
|
274
315
|
end
|
275
316
|
|
@@ -289,7 +330,7 @@ module ActiveRecord
|
|
289
330
|
# This is short-hand for <tt>unscope(:select).select(fields)</tt>.
|
290
331
|
# Note that we're unscoping the entire select statement.
|
291
332
|
def reselect(*args)
|
292
|
-
check_if_method_has_arguments!(
|
333
|
+
check_if_method_has_arguments!(__callee__, args)
|
293
334
|
spawn.reselect!(*args)
|
294
335
|
end
|
295
336
|
|
@@ -320,7 +361,7 @@ module ActiveRecord
|
|
320
361
|
# User.select([:id, :first_name]).group(:id, :first_name).first(3)
|
321
362
|
# # => [#<User id: 1, first_name: "Bill">, #<User id: 2, first_name: "Earl">, #<User id: 3, first_name: "Beto">]
|
322
363
|
def group(*args)
|
323
|
-
check_if_method_has_arguments!(
|
364
|
+
check_if_method_has_arguments!(__callee__, args)
|
324
365
|
spawn.group!(*args)
|
325
366
|
end
|
326
367
|
|
@@ -329,17 +370,37 @@ module ActiveRecord
|
|
329
370
|
self
|
330
371
|
end
|
331
372
|
|
332
|
-
#
|
373
|
+
# Applies an <code>ORDER BY</code> clause to a query.
|
374
|
+
#
|
375
|
+
# #order accepts arguments in one of several formats.
|
376
|
+
#
|
377
|
+
# === symbols
|
378
|
+
#
|
379
|
+
# The symbol represents the name of the column you want to order the results by.
|
333
380
|
#
|
334
381
|
# User.order(:name)
|
335
382
|
# # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
|
336
383
|
#
|
384
|
+
# By default, the order is ascending. If you want descending order, you can
|
385
|
+
# map the column name symbol to +:desc+.
|
386
|
+
#
|
337
387
|
# User.order(email: :desc)
|
338
388
|
# # SELECT "users".* FROM "users" ORDER BY "users"."email" DESC
|
339
389
|
#
|
390
|
+
# Multiple columns can be passed this way, and they will be applied in the order specified.
|
391
|
+
#
|
340
392
|
# User.order(:name, email: :desc)
|
341
393
|
# # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
|
342
394
|
#
|
395
|
+
# === strings
|
396
|
+
#
|
397
|
+
# Strings are passed directly to the database, allowing you to specify
|
398
|
+
# simple SQL expressions.
|
399
|
+
#
|
400
|
+
# This could be a source of SQL injection, so only strings composed of plain
|
401
|
+
# column names and simple <code>function(column_name)</code> expressions
|
402
|
+
# with optional +ASC+/+DESC+ modifiers are allowed.
|
403
|
+
#
|
343
404
|
# User.order('name')
|
344
405
|
# # SELECT "users".* FROM "users" ORDER BY name
|
345
406
|
#
|
@@ -348,8 +409,21 @@ module ActiveRecord
|
|
348
409
|
#
|
349
410
|
# User.order('name DESC, email')
|
350
411
|
# # SELECT "users".* FROM "users" ORDER BY name DESC, email
|
412
|
+
#
|
413
|
+
# === Arel
|
414
|
+
#
|
415
|
+
# If you need to pass in complicated expressions that you have verified
|
416
|
+
# are safe for the database, you can use Arel.
|
417
|
+
#
|
418
|
+
# User.order(Arel.sql('end_date - start_date'))
|
419
|
+
# # SELECT "users".* FROM "users" ORDER BY end_date - start_date
|
420
|
+
#
|
421
|
+
# Custom query syntax, like JSON columns for Postgres, is supported in this way.
|
422
|
+
#
|
423
|
+
# User.order(Arel.sql("payload->>'kind'"))
|
424
|
+
# # SELECT "users".* FROM "users" ORDER BY payload->>'kind'
|
351
425
|
def order(*args)
|
352
|
-
check_if_method_has_arguments!(
|
426
|
+
check_if_method_has_arguments!(__callee__, args) do
|
353
427
|
sanitize_order_arguments(args)
|
354
428
|
end
|
355
429
|
spawn.order!(*args)
|
@@ -362,6 +436,29 @@ module ActiveRecord
|
|
362
436
|
self
|
363
437
|
end
|
364
438
|
|
439
|
+
# Allows to specify an order by a specific set of values. Depending on your
|
440
|
+
# adapter this will either use a CASE statement or a built-in function.
|
441
|
+
#
|
442
|
+
# User.in_order_of(:id, [1, 5, 3])
|
443
|
+
# # SELECT "users".* FROM "users"
|
444
|
+
# # ORDER BY FIELD("users"."id", 1, 5, 3)
|
445
|
+
# # WHERE "users"."id" IN (1, 5, 3)
|
446
|
+
#
|
447
|
+
def in_order_of(column, values)
|
448
|
+
klass.disallow_raw_sql!([column], permit: connection.column_name_with_order_matcher)
|
449
|
+
return spawn.none! if values.empty?
|
450
|
+
|
451
|
+
references = column_references([column])
|
452
|
+
self.references_values |= references unless references.empty?
|
453
|
+
|
454
|
+
values = values.map { |value| type_caster.type_cast_for_database(column, value) }
|
455
|
+
arel_column = column.is_a?(Symbol) ? order_column(column.to_s) : column
|
456
|
+
|
457
|
+
spawn
|
458
|
+
.order!(connection.field_ordered_value(arel_column, values))
|
459
|
+
.where!(arel_column.in(values))
|
460
|
+
end
|
461
|
+
|
365
462
|
# Replaces any existing order defined on the relation with the specified order.
|
366
463
|
#
|
367
464
|
# User.order('email DESC').reorder('id ASC') # generated SQL has 'ORDER BY id ASC'
|
@@ -372,15 +469,15 @@ module ActiveRecord
|
|
372
469
|
#
|
373
470
|
# generates a query with 'ORDER BY id ASC, name ASC'.
|
374
471
|
def reorder(*args)
|
375
|
-
check_if_method_has_arguments!(
|
376
|
-
sanitize_order_arguments(args)
|
472
|
+
check_if_method_has_arguments!(__callee__, args) do
|
473
|
+
sanitize_order_arguments(args)
|
377
474
|
end
|
378
475
|
spawn.reorder!(*args)
|
379
476
|
end
|
380
477
|
|
381
478
|
# Same as #reorder but operates on relation in-place instead of copying.
|
382
479
|
def reorder!(*args) # :nodoc:
|
383
|
-
preprocess_order_args(args)
|
480
|
+
preprocess_order_args(args)
|
384
481
|
args.uniq!
|
385
482
|
self.reordering_value = true
|
386
483
|
self.order_values = args
|
@@ -425,7 +522,7 @@ module ActiveRecord
|
|
425
522
|
# has_many :comments, -> { unscope(where: :trashed) }
|
426
523
|
#
|
427
524
|
def unscope(*args)
|
428
|
-
check_if_method_has_arguments!(
|
525
|
+
check_if_method_has_arguments!(__callee__, args)
|
429
526
|
spawn.unscope!(*args)
|
430
527
|
end
|
431
528
|
|
@@ -458,7 +555,7 @@ module ActiveRecord
|
|
458
555
|
self
|
459
556
|
end
|
460
557
|
|
461
|
-
# Performs
|
558
|
+
# Performs JOINs on +args+. The given symbol(s) should match the name of
|
462
559
|
# the association(s).
|
463
560
|
#
|
464
561
|
# User.joins(:posts)
|
@@ -487,7 +584,7 @@ module ActiveRecord
|
|
487
584
|
# User.joins("LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id")
|
488
585
|
# # SELECT "users".* FROM "users" LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id
|
489
586
|
def joins(*args)
|
490
|
-
check_if_method_has_arguments!(
|
587
|
+
check_if_method_has_arguments!(__callee__, args)
|
491
588
|
spawn.joins!(*args)
|
492
589
|
end
|
493
590
|
|
@@ -496,7 +593,7 @@ module ActiveRecord
|
|
496
593
|
self
|
497
594
|
end
|
498
595
|
|
499
|
-
# Performs
|
596
|
+
# Performs LEFT OUTER JOINs on +args+:
|
500
597
|
#
|
501
598
|
# User.left_outer_joins(:posts)
|
502
599
|
# => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
|
@@ -578,13 +675,13 @@ module ActiveRecord
|
|
578
675
|
#
|
579
676
|
# Fields can be symbols or strings. Values can be single values, arrays, or ranges.
|
580
677
|
#
|
581
|
-
# User.where(
|
678
|
+
# User.where(name: "Joe", email: "joe@example.com")
|
582
679
|
# # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com'
|
583
680
|
#
|
584
|
-
# User.where(
|
681
|
+
# User.where(name: ["Alice", "Bob"])
|
585
682
|
# # SELECT * FROM users WHERE name IN ('Alice', 'Bob')
|
586
683
|
#
|
587
|
-
# User.where(
|
684
|
+
# User.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)
|
588
685
|
# # SELECT * FROM users WHERE (created_at BETWEEN '2012-06-09 07:00:00.000000' AND '2012-06-10 07:00:00.000000')
|
589
686
|
#
|
590
687
|
# In the case of a belongs_to relationship, an association key can be used
|
@@ -614,18 +711,32 @@ module ActiveRecord
|
|
614
711
|
#
|
615
712
|
# For hash conditions, you can either use the table name in the key, or use a sub-hash.
|
616
713
|
#
|
617
|
-
# User.joins(:posts).where(
|
618
|
-
# User.joins(:posts).where(
|
714
|
+
# User.joins(:posts).where("posts.published" => true)
|
715
|
+
# User.joins(:posts).where(posts: { published: true })
|
619
716
|
#
|
620
717
|
# === no argument
|
621
718
|
#
|
622
719
|
# If no argument is passed, #where returns a new instance of WhereChain, that
|
623
|
-
# can be chained with #not
|
720
|
+
# can be chained with WhereChain#not, WhereChain#missing, or WhereChain#associated.
|
721
|
+
#
|
722
|
+
# Chaining with WhereChain#not:
|
624
723
|
#
|
625
724
|
# User.where.not(name: "Jon")
|
626
725
|
# # SELECT * FROM users WHERE name != 'Jon'
|
627
726
|
#
|
628
|
-
#
|
727
|
+
# Chaining with WhereChain#associated:
|
728
|
+
#
|
729
|
+
# Post.where.associated(:author)
|
730
|
+
# # SELECT "posts".* FROM "posts"
|
731
|
+
# # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
732
|
+
# # WHERE "authors"."id" IS NOT NULL
|
733
|
+
#
|
734
|
+
# Chaining with WhereChain#missing:
|
735
|
+
#
|
736
|
+
# Post.where.missing(:author)
|
737
|
+
# # SELECT "posts".* FROM "posts"
|
738
|
+
# # LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
739
|
+
# # WHERE "authors"."id" IS NULL
|
629
740
|
#
|
630
741
|
# === blank condition
|
631
742
|
#
|
@@ -668,6 +779,59 @@ module ActiveRecord
|
|
668
779
|
scope
|
669
780
|
end
|
670
781
|
|
782
|
+
# Allows you to invert an entire where clause instead of manually applying conditions.
|
783
|
+
#
|
784
|
+
# class User
|
785
|
+
# scope :active, -> { where(accepted: true, locked: false) }
|
786
|
+
# end
|
787
|
+
#
|
788
|
+
# User.where(accepted: true)
|
789
|
+
# # WHERE `accepted` = 1
|
790
|
+
#
|
791
|
+
# User.where(accepted: true).invert_where
|
792
|
+
# # WHERE `accepted` != 1
|
793
|
+
#
|
794
|
+
# User.active
|
795
|
+
# # WHERE `accepted` = 1 AND `locked` = 0
|
796
|
+
#
|
797
|
+
# User.active.invert_where
|
798
|
+
# # WHERE NOT (`accepted` = 1 AND `locked` = 0)
|
799
|
+
#
|
800
|
+
# Be careful because this inverts all conditions before +invert_where+ call.
|
801
|
+
#
|
802
|
+
# class User
|
803
|
+
# scope :active, -> { where(accepted: true, locked: false) }
|
804
|
+
# scope :inactive, -> { active.invert_where } # Do not attempt it
|
805
|
+
# end
|
806
|
+
#
|
807
|
+
# # It also inverts `where(role: 'admin')` unexpectedly.
|
808
|
+
# User.where(role: 'admin').inactive
|
809
|
+
# # WHERE NOT (`role` = 'admin' AND `accepted` = 1 AND `locked` = 0)
|
810
|
+
#
|
811
|
+
def invert_where
|
812
|
+
spawn.invert_where!
|
813
|
+
end
|
814
|
+
|
815
|
+
def invert_where! # :nodoc:
|
816
|
+
self.where_clause = where_clause.invert
|
817
|
+
self
|
818
|
+
end
|
819
|
+
|
820
|
+
# Checks whether the given relation is structurally compatible with this relation, to determine
|
821
|
+
# if it's possible to use the #and and #or methods without raising an error. Structurally
|
822
|
+
# compatible is defined as: they must be scoping the same model, and they must differ only by
|
823
|
+
# #where (if no #group has been defined) or #having (if a #group is present).
|
824
|
+
#
|
825
|
+
# Post.where("id = 1").structurally_compatible?(Post.where("author_id = 3"))
|
826
|
+
# # => true
|
827
|
+
#
|
828
|
+
# Post.joins(:comments).structurally_compatible?(Post.where("id = 1"))
|
829
|
+
# # => false
|
830
|
+
#
|
831
|
+
def structurally_compatible?(other)
|
832
|
+
structurally_incompatible_values_for(other).empty?
|
833
|
+
end
|
834
|
+
|
671
835
|
# Returns a new relation, which is the logical intersection of this relation and the one passed
|
672
836
|
# as an argument.
|
673
837
|
#
|
@@ -886,7 +1050,7 @@ module ActiveRecord
|
|
886
1050
|
self
|
887
1051
|
end
|
888
1052
|
|
889
|
-
# Specifies table from which the records will be fetched. For example:
|
1053
|
+
# Specifies the table from which the records will be fetched. For example:
|
890
1054
|
#
|
891
1055
|
# Topic.select('title').from('posts')
|
892
1056
|
# # SELECT title FROM posts
|
@@ -896,9 +1060,26 @@ module ActiveRecord
|
|
896
1060
|
# Topic.select('title').from(Topic.approved)
|
897
1061
|
# # SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery
|
898
1062
|
#
|
1063
|
+
# Passing a second argument (string or symbol), creates the alias for the SQL from clause. Otherwise the alias "subquery" is used:
|
1064
|
+
#
|
899
1065
|
# Topic.select('a.title').from(Topic.approved, :a)
|
900
1066
|
# # SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a
|
901
1067
|
#
|
1068
|
+
# It does not add multiple arguments to the SQL from clause. The last +from+ chained is the one used:
|
1069
|
+
#
|
1070
|
+
# Topic.select('title').from(Topic.approved).from(Topic.inactive)
|
1071
|
+
# # SELECT title FROM (SELECT topics.* FROM topics WHERE topics.active = 'f') subquery
|
1072
|
+
#
|
1073
|
+
# For multiple arguments for the SQL from clause, you can pass a string with the exact elements in the SQL from list:
|
1074
|
+
#
|
1075
|
+
# color = "red"
|
1076
|
+
# Color
|
1077
|
+
# .from("colors c, JSONB_ARRAY_ELEMENTS(colored_things) AS colorvalues(colorvalue)")
|
1078
|
+
# .where("colorvalue->>'color' = ?", color)
|
1079
|
+
# .select("c.*").to_a
|
1080
|
+
# # SELECT c.*
|
1081
|
+
# # FROM colors c, JSONB_ARRAY_ELEMENTS(colored_things) AS colorvalues(colorvalue)
|
1082
|
+
# # WHERE (colorvalue->>'color' = 'red')
|
902
1083
|
def from(value, subquery_name = nil)
|
903
1084
|
spawn.from!(value, subquery_name)
|
904
1085
|
end
|
@@ -994,7 +1175,7 @@ module ActiveRecord
|
|
994
1175
|
# Topic.optimizer_hints("SeqScan(topics)", "Parallel(topics 8)")
|
995
1176
|
# # SELECT /*+ SeqScan(topics) Parallel(topics 8) */ "topics".* FROM "topics"
|
996
1177
|
def optimizer_hints(*args)
|
997
|
-
check_if_method_has_arguments!(
|
1178
|
+
check_if_method_has_arguments!(__callee__, args)
|
998
1179
|
spawn.optimizer_hints!(*args)
|
999
1180
|
end
|
1000
1181
|
|
@@ -1036,7 +1217,7 @@ module ActiveRecord
|
|
1036
1217
|
#
|
1037
1218
|
# The SQL block comment delimiters, "/*" and "*/", will be added automatically.
|
1038
1219
|
def annotate(*args)
|
1039
|
-
check_if_method_has_arguments!(
|
1220
|
+
check_if_method_has_arguments!(__callee__, args)
|
1040
1221
|
spawn.annotate!(*args)
|
1041
1222
|
end
|
1042
1223
|
|
@@ -1054,6 +1235,47 @@ module ActiveRecord
|
|
1054
1235
|
self
|
1055
1236
|
end
|
1056
1237
|
|
1238
|
+
# Excludes the specified record (or collection of records) from the resulting
|
1239
|
+
# relation. For example:
|
1240
|
+
#
|
1241
|
+
# Post.excluding(post)
|
1242
|
+
# # SELECT "posts".* FROM "posts" WHERE "posts"."id" != 1
|
1243
|
+
#
|
1244
|
+
# Post.excluding(post_one, post_two)
|
1245
|
+
# # SELECT "posts".* FROM "posts" WHERE "posts"."id" NOT IN (1, 2)
|
1246
|
+
#
|
1247
|
+
# This can also be called on associations. As with the above example, either
|
1248
|
+
# a single record of collection thereof may be specified:
|
1249
|
+
#
|
1250
|
+
# post = Post.find(1)
|
1251
|
+
# comment = Comment.find(2)
|
1252
|
+
# post.comments.excluding(comment)
|
1253
|
+
# # SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 AND "comments"."id" != 2
|
1254
|
+
#
|
1255
|
+
# This is short-hand for <tt>.where.not(id: post.id)</tt> and <tt>.where.not(id: [post_one.id, post_two.id])</tt>.
|
1256
|
+
#
|
1257
|
+
# An <tt>ArgumentError</tt> will be raised if either no records are
|
1258
|
+
# specified, or if any of the records in the collection (if a collection
|
1259
|
+
# is passed in) are not instances of the same model that the relation is
|
1260
|
+
# scoping.
|
1261
|
+
def excluding(*records)
|
1262
|
+
records.flatten!(1)
|
1263
|
+
records.compact!
|
1264
|
+
|
1265
|
+
unless records.all?(klass)
|
1266
|
+
raise ArgumentError, "You must only pass a single or collection of #{klass.name} objects to ##{__callee__}."
|
1267
|
+
end
|
1268
|
+
|
1269
|
+
spawn.excluding!(records)
|
1270
|
+
end
|
1271
|
+
alias :without :excluding
|
1272
|
+
|
1273
|
+
def excluding!(records) # :nodoc:
|
1274
|
+
predicates = [ predicate_builder[primary_key, records].invert ]
|
1275
|
+
self.where_clause += Relation::WhereClause.new(predicates)
|
1276
|
+
self
|
1277
|
+
end
|
1278
|
+
|
1057
1279
|
# Returns the Arel object associated with the relation.
|
1058
1280
|
def arel(aliases = nil) # :nodoc:
|
1059
1281
|
@arel ||= build_arel(aliases)
|
@@ -1109,11 +1331,9 @@ module ActiveRecord
|
|
1109
1331
|
nil
|
1110
1332
|
end
|
1111
1333
|
|
1112
|
-
def each_join_dependencies(join_dependencies = build_join_dependencies)
|
1334
|
+
def each_join_dependencies(join_dependencies = build_join_dependencies, &block)
|
1113
1335
|
join_dependencies.each do |join_dependency|
|
1114
|
-
join_dependency.each
|
1115
|
-
yield join
|
1116
|
-
end
|
1336
|
+
join_dependency.each(&block)
|
1117
1337
|
end
|
1118
1338
|
end
|
1119
1339
|
|
@@ -1155,14 +1375,6 @@ module ActiveRecord
|
|
1155
1375
|
unless annotate_values.empty?
|
1156
1376
|
annotates = annotate_values
|
1157
1377
|
annotates = annotates.uniq if annotates.size > 1
|
1158
|
-
unless annotates == annotate_values
|
1159
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
1160
|
-
Duplicated query annotations are no longer shown in queries in Rails 7.0.
|
1161
|
-
To migrate to Rails 7.0's behavior, use `uniq!(:annotate)` to deduplicate query annotations
|
1162
|
-
(`#{klass.name&.tableize || klass.table_name}.uniq!(:annotate)`).
|
1163
|
-
MSG
|
1164
|
-
annotates = annotate_values
|
1165
|
-
end
|
1166
1378
|
arel.comment(*annotates)
|
1167
1379
|
end
|
1168
1380
|
|
@@ -1170,8 +1382,7 @@ module ActiveRecord
|
|
1170
1382
|
end
|
1171
1383
|
|
1172
1384
|
def build_cast_value(name, value)
|
1173
|
-
|
1174
|
-
Arel::Nodes::BindParam.new(cast_value)
|
1385
|
+
ActiveModel::Attribute.with_cast_value(name, value, Type.default_value)
|
1175
1386
|
end
|
1176
1387
|
|
1177
1388
|
def build_from
|
@@ -1282,7 +1493,7 @@ module ActiveRecord
|
|
1282
1493
|
def build_select(arel)
|
1283
1494
|
if select_values.any?
|
1284
1495
|
arel.project(*arel_columns(select_values))
|
1285
|
-
elsif klass.ignored_columns.any?
|
1496
|
+
elsif klass.ignored_columns.any? || klass.enumerate_columns_in_select_statements
|
1286
1497
|
arel.project(*klass.column_names.map { |field| table[field] })
|
1287
1498
|
else
|
1288
1499
|
arel.project(table[Arel.star])
|
@@ -1423,12 +1634,17 @@ module ActiveRecord
|
|
1423
1634
|
order_args.map! do |arg|
|
1424
1635
|
klass.sanitize_sql_for_order(arg)
|
1425
1636
|
end
|
1426
|
-
order_args.flatten!
|
1427
|
-
order_args.compact_blank!
|
1428
1637
|
end
|
1429
1638
|
|
1430
1639
|
def column_references(order_args)
|
1431
|
-
references = order_args.
|
1640
|
+
references = order_args.flat_map do |arg|
|
1641
|
+
case arg
|
1642
|
+
when String, Symbol
|
1643
|
+
arg
|
1644
|
+
when Hash
|
1645
|
+
arg.keys
|
1646
|
+
end
|
1647
|
+
end
|
1432
1648
|
references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
|
1433
1649
|
references
|
1434
1650
|
end
|
@@ -1476,19 +1692,19 @@ module ActiveRecord
|
|
1476
1692
|
# Post.references() # raises an error
|
1477
1693
|
# Post.references([]) # does not raise an error
|
1478
1694
|
#
|
1479
|
-
# This particular method should be called with a method_name and the args
|
1695
|
+
# This particular method should be called with a method_name (__callee__) and the args
|
1480
1696
|
# passed into that method as an input. For example:
|
1481
1697
|
#
|
1482
1698
|
# def references(*args)
|
1483
|
-
# check_if_method_has_arguments!(
|
1699
|
+
# check_if_method_has_arguments!(__callee__, args)
|
1484
1700
|
# ...
|
1485
1701
|
# end
|
1486
1702
|
def check_if_method_has_arguments!(method_name, args, message = nil)
|
1487
1703
|
if args.blank?
|
1488
1704
|
raise ArgumentError, message || "The method .#{method_name}() must contain arguments."
|
1489
|
-
elsif block_given?
|
1490
|
-
yield args
|
1491
1705
|
else
|
1706
|
+
yield args if block_given?
|
1707
|
+
|
1492
1708
|
args.flatten!
|
1493
1709
|
args.compact_blank!
|
1494
1710
|
end
|
@@ -1512,11 +1728,4 @@ module ActiveRecord
|
|
1512
1728
|
end
|
1513
1729
|
end
|
1514
1730
|
end
|
1515
|
-
|
1516
|
-
class Relation # :nodoc:
|
1517
|
-
# No-op WhereClauseFactory to work Mashal.load(File.read("legacy_relation.dump")).
|
1518
|
-
# TODO: Remove the class once Rails 6.1 has released.
|
1519
|
-
class WhereClauseFactory # :nodoc:
|
1520
|
-
end
|
1521
|
-
end
|
1522
1731
|
end
|
@@ -17,8 +17,8 @@ module ActiveRecord
|
|
17
17
|
QueryRegistry.reset
|
18
18
|
|
19
19
|
super.tap do |records|
|
20
|
-
if logger && warn_on_records_fetched_greater_than
|
21
|
-
if records.length > warn_on_records_fetched_greater_than
|
20
|
+
if logger && ActiveRecord.warn_on_records_fetched_greater_than
|
21
|
+
if records.length > ActiveRecord.warn_on_records_fetched_greater_than
|
22
22
|
logger.warn "Query fetched #{records.size} #{@klass} records: #{QueryRegistry.queries.join(";")}"
|
23
23
|
end
|
24
24
|
end
|
@@ -31,17 +31,15 @@ module ActiveRecord
|
|
31
31
|
end
|
32
32
|
# :startdoc:
|
33
33
|
|
34
|
-
|
35
|
-
extend
|
34
|
+
module QueryRegistry # :nodoc:
|
35
|
+
extend self
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
def initialize
|
40
|
-
@queries = []
|
37
|
+
def queries
|
38
|
+
ActiveSupport::IsolatedExecutionState[:active_record_query_registry] ||= []
|
41
39
|
end
|
42
40
|
|
43
41
|
def reset
|
44
|
-
|
42
|
+
queries.clear
|
45
43
|
end
|
46
44
|
end
|
47
45
|
end
|
@@ -7,8 +7,8 @@ require "active_record/relation/merger"
|
|
7
7
|
module ActiveRecord
|
8
8
|
module SpawnMethods
|
9
9
|
# This is overridden by Associations::CollectionProxy
|
10
|
-
def spawn
|
11
|
-
already_in_scope? ? klass.all : clone
|
10
|
+
def spawn # :nodoc:
|
11
|
+
already_in_scope?(klass.scope_registry) ? klass.all : clone
|
12
12
|
end
|
13
13
|
|
14
14
|
# Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
|