activerecord 6.1.4.6 → 7.0.2.3
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.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1188 -932
- data/MIT-LICENSE +1 -1
- 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 +34 -27
- data/lib/active_record/associations/collection_proxy.rb +8 -3
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/has_many_association.rb +1 -1
- 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 +6 -2
- data/lib/active_record/associations/preloader/association.rb +187 -55
- 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 +119 -90
- 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 +66 -12
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
- data/lib/active_record/attribute_methods/write.rb +7 -10
- data/lib/active_record/attribute_methods.rb +13 -14
- 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/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 +78 -22
- 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 +97 -81
- data/lib/active_record/connection_adapters/column.rb +4 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +38 -24
- data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +5 -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 +21 -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 +50 -50
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -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 +35 -19
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -107
- data/lib/active_record/connection_adapters/schema_cache.rb +29 -4
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +27 -19
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +16 -14
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +89 -30
- data/lib/active_record/connection_adapters.rb +6 -5
- data/lib/active_record/connection_handling.rb +47 -53
- data/lib/active_record/core.rb +122 -132
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -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 +16 -32
- data/lib/active_record/delegated_type.rb +52 -11
- 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 +61 -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 +208 -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 +49 -42
- 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 +17 -20
- 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 +3 -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 +9 -3
- data/lib/active_record/log_subscriber.rb +14 -3
- data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
- data/lib/active_record/middleware/database_selector.rb +8 -3
- data/lib/active_record/middleware/shard_selector.rb +60 -0
- data/lib/active_record/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +107 -3
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +109 -79
- data/lib/active_record/model_schema.rb +45 -58
- 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 +219 -52
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +138 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +127 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +66 -129
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +67 -50
- data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
- data/lib/active_record/relation/batches.rb +3 -3
- 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 +249 -61
- 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 +184 -84
- data/lib/active_record/result.rb +17 -7
- data/lib/active_record/runtime_registry.rb +9 -13
- data/lib/active_record/sanitization.rb +11 -7
- 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 +61 -12
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +64 -34
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/tasks/database_tasks.rb +120 -58
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +4 -4
- data/lib/active_record/timestamp.rb +3 -4
- data/lib/active_record/transactions.rb +9 -14
- data/lib/active_record/translation.rb +2 -2
- 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 +1 -1
- data/lib/active_record/validations/uniqueness.rb +1 -1
- data/lib/active_record.rb +204 -28
- 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 +56 -11
@@ -8,8 +8,6 @@ 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
13
|
# WhereChain objects act as placeholder for queries in which #where does not have any parameter.
|
@@ -50,6 +48,34 @@ module ActiveRecord
|
|
50
48
|
@scope
|
51
49
|
end
|
52
50
|
|
51
|
+
# Returns a new relation with joins and where clause to identify
|
52
|
+
# associated relations.
|
53
|
+
#
|
54
|
+
# For example, posts that are associated to a related author:
|
55
|
+
#
|
56
|
+
# Post.where.associated(:author)
|
57
|
+
# # SELECT "posts".* FROM "posts"
|
58
|
+
# # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
59
|
+
# # WHERE "authors"."id" IS NOT NULL
|
60
|
+
#
|
61
|
+
# Additionally, multiple relations can be combined. This will return posts
|
62
|
+
# associated to both an author and any comments:
|
63
|
+
#
|
64
|
+
# Post.where.associated(:author, :comments)
|
65
|
+
# # SELECT "posts".* FROM "posts"
|
66
|
+
# # INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
67
|
+
# # INNER JOIN "comments" ON "comments"."post_id" = "posts"."id"
|
68
|
+
# # WHERE "authors"."id" IS NOT NULL AND "comments"."id" IS NOT NULL
|
69
|
+
def associated(*associations)
|
70
|
+
associations.each do |association|
|
71
|
+
reflection = scope_association_reflection(association)
|
72
|
+
@scope.joins!(association)
|
73
|
+
self.not(reflection.table_name => { reflection.association_primary_key => nil })
|
74
|
+
end
|
75
|
+
|
76
|
+
@scope
|
77
|
+
end
|
78
|
+
|
53
79
|
# Returns a new relation with left outer joins and where clause to identify
|
54
80
|
# missing relations.
|
55
81
|
#
|
@@ -68,16 +94,24 @@ module ActiveRecord
|
|
68
94
|
# # LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
|
69
95
|
# # LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id"
|
70
96
|
# # WHERE "authors"."id" IS NULL AND "comments"."id" IS NULL
|
71
|
-
def missing(*
|
72
|
-
|
73
|
-
reflection =
|
74
|
-
|
75
|
-
@scope.
|
76
|
-
@scope.where!(opts)
|
97
|
+
def missing(*associations)
|
98
|
+
associations.each do |association|
|
99
|
+
reflection = scope_association_reflection(association)
|
100
|
+
@scope.left_outer_joins!(association)
|
101
|
+
@scope.where!(reflection.table_name => { reflection.association_primary_key => nil })
|
77
102
|
end
|
78
103
|
|
79
104
|
@scope
|
80
105
|
end
|
106
|
+
|
107
|
+
private
|
108
|
+
def scope_association_reflection(association)
|
109
|
+
reflection = @scope.klass._reflect_on_association(association)
|
110
|
+
unless reflection
|
111
|
+
raise ArgumentError.new("An association named `:#{association}` does not exist on the model `#{@scope.name}`.")
|
112
|
+
end
|
113
|
+
reflection
|
114
|
+
end
|
81
115
|
end
|
82
116
|
|
83
117
|
FROZEN_EMPTY_ARRAY = [].freeze
|
@@ -148,7 +182,7 @@ module ActiveRecord
|
|
148
182
|
#
|
149
183
|
# User.includes(:posts).where(posts: { name: 'example' })
|
150
184
|
def includes(*args)
|
151
|
-
check_if_method_has_arguments!(
|
185
|
+
check_if_method_has_arguments!(__callee__, args)
|
152
186
|
spawn.includes!(*args)
|
153
187
|
end
|
154
188
|
|
@@ -164,7 +198,7 @@ module ActiveRecord
|
|
164
198
|
# # FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" =
|
165
199
|
# # "users"."id"
|
166
200
|
def eager_load(*args)
|
167
|
-
check_if_method_has_arguments!(
|
201
|
+
check_if_method_has_arguments!(__callee__, args)
|
168
202
|
spawn.eager_load!(*args)
|
169
203
|
end
|
170
204
|
|
@@ -178,7 +212,7 @@ module ActiveRecord
|
|
178
212
|
# User.preload(:posts)
|
179
213
|
# # SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1, 2, 3)
|
180
214
|
def preload(*args)
|
181
|
-
check_if_method_has_arguments!(
|
215
|
+
check_if_method_has_arguments!(__callee__, args)
|
182
216
|
spawn.preload!(*args)
|
183
217
|
end
|
184
218
|
|
@@ -211,7 +245,7 @@ module ActiveRecord
|
|
211
245
|
# User.includes(:posts).where("posts.name = 'foo'").references(:posts)
|
212
246
|
# # Query now knows the string references posts, so adds a JOIN
|
213
247
|
def references(*table_names)
|
214
|
-
check_if_method_has_arguments!(
|
248
|
+
check_if_method_has_arguments!(__callee__, table_names)
|
215
249
|
spawn.references!(*table_names)
|
216
250
|
end
|
217
251
|
|
@@ -269,7 +303,7 @@ module ActiveRecord
|
|
269
303
|
return super()
|
270
304
|
end
|
271
305
|
|
272
|
-
check_if_method_has_arguments!(
|
306
|
+
check_if_method_has_arguments!(__callee__, fields, "Call `select' with at least one field.")
|
273
307
|
spawn._select!(*fields)
|
274
308
|
end
|
275
309
|
|
@@ -289,7 +323,7 @@ module ActiveRecord
|
|
289
323
|
# This is short-hand for <tt>unscope(:select).select(fields)</tt>.
|
290
324
|
# Note that we're unscoping the entire select statement.
|
291
325
|
def reselect(*args)
|
292
|
-
check_if_method_has_arguments!(
|
326
|
+
check_if_method_has_arguments!(__callee__, args)
|
293
327
|
spawn.reselect!(*args)
|
294
328
|
end
|
295
329
|
|
@@ -320,7 +354,7 @@ module ActiveRecord
|
|
320
354
|
# User.select([:id, :first_name]).group(:id, :first_name).first(3)
|
321
355
|
# # => [#<User id: 1, first_name: "Bill">, #<User id: 2, first_name: "Earl">, #<User id: 3, first_name: "Beto">]
|
322
356
|
def group(*args)
|
323
|
-
check_if_method_has_arguments!(
|
357
|
+
check_if_method_has_arguments!(__callee__, args)
|
324
358
|
spawn.group!(*args)
|
325
359
|
end
|
326
360
|
|
@@ -329,17 +363,37 @@ module ActiveRecord
|
|
329
363
|
self
|
330
364
|
end
|
331
365
|
|
332
|
-
#
|
366
|
+
# Applies an <code>ORDER BY</code> clause to a query.
|
367
|
+
#
|
368
|
+
# #order accepts arguments in one of several formats.
|
369
|
+
#
|
370
|
+
# === symbols
|
371
|
+
#
|
372
|
+
# The symbol represents the name of the column you want to order the results by.
|
333
373
|
#
|
334
374
|
# User.order(:name)
|
335
375
|
# # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
|
336
376
|
#
|
377
|
+
# By default, the order is ascending. If you want descending order, you can
|
378
|
+
# map the column name symbol to +:desc+.
|
379
|
+
#
|
337
380
|
# User.order(email: :desc)
|
338
381
|
# # SELECT "users".* FROM "users" ORDER BY "users"."email" DESC
|
339
382
|
#
|
383
|
+
# Multiple columns can be passed this way, and they will be applied in the order specified.
|
384
|
+
#
|
340
385
|
# User.order(:name, email: :desc)
|
341
386
|
# # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
|
342
387
|
#
|
388
|
+
# === strings
|
389
|
+
#
|
390
|
+
# Strings are passed directly to the database, allowing you to specify
|
391
|
+
# simple SQL expressions.
|
392
|
+
#
|
393
|
+
# This could be a source of SQL injection, so only strings composed of plain
|
394
|
+
# column names and simple <code>function(column_name)</code> expressions
|
395
|
+
# with optional +ASC+/+DESC+ modifiers are allowed.
|
396
|
+
#
|
343
397
|
# User.order('name')
|
344
398
|
# # SELECT "users".* FROM "users" ORDER BY name
|
345
399
|
#
|
@@ -348,8 +402,21 @@ module ActiveRecord
|
|
348
402
|
#
|
349
403
|
# User.order('name DESC, email')
|
350
404
|
# # SELECT "users".* FROM "users" ORDER BY name DESC, email
|
405
|
+
#
|
406
|
+
# === Arel
|
407
|
+
#
|
408
|
+
# If you need to pass in complicated expressions that you have verified
|
409
|
+
# are safe for the database, you can use Arel.
|
410
|
+
#
|
411
|
+
# User.order(Arel.sql('end_date - start_date'))
|
412
|
+
# # SELECT "users".* FROM "users" ORDER BY end_date - start_date
|
413
|
+
#
|
414
|
+
# Custom query syntax, like JSON columns for Postgres, is supported in this way.
|
415
|
+
#
|
416
|
+
# User.order(Arel.sql("payload->>'kind'"))
|
417
|
+
# # SELECT "users".* FROM "users" ORDER BY payload->>'kind'
|
351
418
|
def order(*args)
|
352
|
-
check_if_method_has_arguments!(
|
419
|
+
check_if_method_has_arguments!(__callee__, args) do
|
353
420
|
sanitize_order_arguments(args)
|
354
421
|
end
|
355
422
|
spawn.order!(*args)
|
@@ -362,6 +429,29 @@ module ActiveRecord
|
|
362
429
|
self
|
363
430
|
end
|
364
431
|
|
432
|
+
# Allows to specify an order by a specific set of values. Depending on your
|
433
|
+
# adapter this will either use a CASE statement or a built-in function.
|
434
|
+
#
|
435
|
+
# User.in_order_of(:id, [1, 5, 3])
|
436
|
+
# # SELECT "users".* FROM "users"
|
437
|
+
# # ORDER BY FIELD("users"."id", 1, 5, 3)
|
438
|
+
# # WHERE "users"."id" IN (1, 5, 3)
|
439
|
+
#
|
440
|
+
def in_order_of(column, values)
|
441
|
+
klass.disallow_raw_sql!([column], permit: connection.column_name_with_order_matcher)
|
442
|
+
return spawn.none! if values.empty?
|
443
|
+
|
444
|
+
references = column_references([column])
|
445
|
+
self.references_values |= references unless references.empty?
|
446
|
+
|
447
|
+
values = values.map { |value| type_caster.type_cast_for_database(column, value) }
|
448
|
+
arel_column = column.is_a?(Symbol) ? order_column(column.to_s) : column
|
449
|
+
|
450
|
+
spawn
|
451
|
+
.order!(connection.field_ordered_value(arel_column, values))
|
452
|
+
.where!(arel_column.in(values))
|
453
|
+
end
|
454
|
+
|
365
455
|
# Replaces any existing order defined on the relation with the specified order.
|
366
456
|
#
|
367
457
|
# User.order('email DESC').reorder('id ASC') # generated SQL has 'ORDER BY id ASC'
|
@@ -372,15 +462,15 @@ module ActiveRecord
|
|
372
462
|
#
|
373
463
|
# generates a query with 'ORDER BY id ASC, name ASC'.
|
374
464
|
def reorder(*args)
|
375
|
-
check_if_method_has_arguments!(
|
376
|
-
sanitize_order_arguments(args)
|
465
|
+
check_if_method_has_arguments!(__callee__, args) do
|
466
|
+
sanitize_order_arguments(args)
|
377
467
|
end
|
378
468
|
spawn.reorder!(*args)
|
379
469
|
end
|
380
470
|
|
381
471
|
# Same as #reorder but operates on relation in-place instead of copying.
|
382
472
|
def reorder!(*args) # :nodoc:
|
383
|
-
preprocess_order_args(args)
|
473
|
+
preprocess_order_args(args)
|
384
474
|
args.uniq!
|
385
475
|
self.reordering_value = true
|
386
476
|
self.order_values = args
|
@@ -425,7 +515,7 @@ module ActiveRecord
|
|
425
515
|
# has_many :comments, -> { unscope(where: :trashed) }
|
426
516
|
#
|
427
517
|
def unscope(*args)
|
428
|
-
check_if_method_has_arguments!(
|
518
|
+
check_if_method_has_arguments!(__callee__, args)
|
429
519
|
spawn.unscope!(*args)
|
430
520
|
end
|
431
521
|
|
@@ -458,7 +548,7 @@ module ActiveRecord
|
|
458
548
|
self
|
459
549
|
end
|
460
550
|
|
461
|
-
# Performs
|
551
|
+
# Performs JOINs on +args+. The given symbol(s) should match the name of
|
462
552
|
# the association(s).
|
463
553
|
#
|
464
554
|
# User.joins(:posts)
|
@@ -487,7 +577,7 @@ module ActiveRecord
|
|
487
577
|
# User.joins("LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id")
|
488
578
|
# # SELECT "users".* FROM "users" LEFT JOIN bookmarks ON bookmarks.bookmarkable_type = 'Post' AND bookmarks.user_id = users.id
|
489
579
|
def joins(*args)
|
490
|
-
check_if_method_has_arguments!(
|
580
|
+
check_if_method_has_arguments!(__callee__, args)
|
491
581
|
spawn.joins!(*args)
|
492
582
|
end
|
493
583
|
|
@@ -496,7 +586,7 @@ module ActiveRecord
|
|
496
586
|
self
|
497
587
|
end
|
498
588
|
|
499
|
-
# Performs
|
589
|
+
# Performs LEFT OUTER JOINs on +args+:
|
500
590
|
#
|
501
591
|
# User.left_outer_joins(:posts)
|
502
592
|
# => SELECT "users".* FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
|
@@ -578,13 +668,13 @@ module ActiveRecord
|
|
578
668
|
#
|
579
669
|
# Fields can be symbols or strings. Values can be single values, arrays, or ranges.
|
580
670
|
#
|
581
|
-
# User.where(
|
671
|
+
# User.where(name: "Joe", email: "joe@example.com")
|
582
672
|
# # SELECT * FROM users WHERE name = 'Joe' AND email = 'joe@example.com'
|
583
673
|
#
|
584
|
-
# User.where(
|
674
|
+
# User.where(name: ["Alice", "Bob"])
|
585
675
|
# # SELECT * FROM users WHERE name IN ('Alice', 'Bob')
|
586
676
|
#
|
587
|
-
# User.where(
|
677
|
+
# User.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)
|
588
678
|
# # SELECT * FROM users WHERE (created_at BETWEEN '2012-06-09 07:00:00.000000' AND '2012-06-10 07:00:00.000000')
|
589
679
|
#
|
590
680
|
# In the case of a belongs_to relationship, an association key can be used
|
@@ -614,8 +704,8 @@ module ActiveRecord
|
|
614
704
|
#
|
615
705
|
# For hash conditions, you can either use the table name in the key, or use a sub-hash.
|
616
706
|
#
|
617
|
-
# User.joins(:posts).where(
|
618
|
-
# User.joins(:posts).where(
|
707
|
+
# User.joins(:posts).where("posts.published" => true)
|
708
|
+
# User.joins(:posts).where(posts: { published: true })
|
619
709
|
#
|
620
710
|
# === no argument
|
621
711
|
#
|
@@ -668,6 +758,59 @@ module ActiveRecord
|
|
668
758
|
scope
|
669
759
|
end
|
670
760
|
|
761
|
+
# Allows you to invert an entire where clause instead of manually applying conditions.
|
762
|
+
#
|
763
|
+
# class User
|
764
|
+
# scope :active, -> { where(accepted: true, locked: false) }
|
765
|
+
# end
|
766
|
+
#
|
767
|
+
# User.where(accepted: true)
|
768
|
+
# # WHERE `accepted` = 1
|
769
|
+
#
|
770
|
+
# User.where(accepted: true).invert_where
|
771
|
+
# # WHERE `accepted` != 1
|
772
|
+
#
|
773
|
+
# User.active
|
774
|
+
# # WHERE `accepted` = 1 AND `locked` = 0
|
775
|
+
#
|
776
|
+
# User.active.invert_where
|
777
|
+
# # WHERE NOT (`accepted` = 1 AND `locked` = 0)
|
778
|
+
#
|
779
|
+
# Be careful because this inverts all conditions before +invert_where+ call.
|
780
|
+
#
|
781
|
+
# class User
|
782
|
+
# scope :active, -> { where(accepted: true, locked: false) }
|
783
|
+
# scope :inactive, -> { active.invert_where } # Do not attempt it
|
784
|
+
# end
|
785
|
+
#
|
786
|
+
# # It also inverts `where(role: 'admin')` unexpectedly.
|
787
|
+
# User.where(role: 'admin').inactive
|
788
|
+
# # WHERE NOT (`role` = 'admin' AND `accepted` = 1 AND `locked` = 0)
|
789
|
+
#
|
790
|
+
def invert_where
|
791
|
+
spawn.invert_where!
|
792
|
+
end
|
793
|
+
|
794
|
+
def invert_where! # :nodoc:
|
795
|
+
self.where_clause = where_clause.invert
|
796
|
+
self
|
797
|
+
end
|
798
|
+
|
799
|
+
# Checks whether the given relation is structurally compatible with this relation, to determine
|
800
|
+
# if it's possible to use the #and and #or methods without raising an error. Structurally
|
801
|
+
# compatible is defined as: they must be scoping the same model, and they must differ only by
|
802
|
+
# #where (if no #group has been defined) or #having (if a #group is present).
|
803
|
+
#
|
804
|
+
# Post.where("id = 1").structurally_compatible?(Post.where("author_id = 3"))
|
805
|
+
# # => true
|
806
|
+
#
|
807
|
+
# Post.joins(:comments).structurally_compatible?(Post.where("id = 1"))
|
808
|
+
# # => false
|
809
|
+
#
|
810
|
+
def structurally_compatible?(other)
|
811
|
+
structurally_incompatible_values_for(other).empty?
|
812
|
+
end
|
813
|
+
|
671
814
|
# Returns a new relation, which is the logical intersection of this relation and the one passed
|
672
815
|
# as an argument.
|
673
816
|
#
|
@@ -886,7 +1029,7 @@ module ActiveRecord
|
|
886
1029
|
self
|
887
1030
|
end
|
888
1031
|
|
889
|
-
# Specifies table from which the records will be fetched. For example:
|
1032
|
+
# Specifies the table from which the records will be fetched. For example:
|
890
1033
|
#
|
891
1034
|
# Topic.select('title').from('posts')
|
892
1035
|
# # SELECT title FROM posts
|
@@ -896,9 +1039,26 @@ module ActiveRecord
|
|
896
1039
|
# Topic.select('title').from(Topic.approved)
|
897
1040
|
# # SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery
|
898
1041
|
#
|
1042
|
+
# Passing a second argument (string or symbol), creates the alias for the SQL from clause. Otherwise the alias "subquery" is used:
|
1043
|
+
#
|
899
1044
|
# Topic.select('a.title').from(Topic.approved, :a)
|
900
1045
|
# # SELECT a.title FROM (SELECT * FROM topics WHERE approved = 't') a
|
901
1046
|
#
|
1047
|
+
# It does not add multiple arguments to the SQL from clause. The last +from+ chained is the one used:
|
1048
|
+
#
|
1049
|
+
# Topic.select('title').from(Topic.approved).from(Topic.inactive)
|
1050
|
+
# # SELECT title FROM (SELECT topics.* FROM topics WHERE topics.active = 'f') subquery
|
1051
|
+
#
|
1052
|
+
# For multiple arguments for the SQL from clause, you can pass a string with the exact elements in the SQL from list:
|
1053
|
+
#
|
1054
|
+
# color = "red"
|
1055
|
+
# Color
|
1056
|
+
# .from("colors c, JSONB_ARRAY_ELEMENTS(colored_things) AS colorvalues(colorvalue)")
|
1057
|
+
# .where("colorvalue->>'color' = ?", color)
|
1058
|
+
# .select("c.*").to_a
|
1059
|
+
# # SELECT c.*
|
1060
|
+
# # FROM colors c, JSONB_ARRAY_ELEMENTS(colored_things) AS colorvalues(colorvalue)
|
1061
|
+
# # WHERE (colorvalue->>'color' = 'red')
|
902
1062
|
def from(value, subquery_name = nil)
|
903
1063
|
spawn.from!(value, subquery_name)
|
904
1064
|
end
|
@@ -994,7 +1154,7 @@ module ActiveRecord
|
|
994
1154
|
# Topic.optimizer_hints("SeqScan(topics)", "Parallel(topics 8)")
|
995
1155
|
# # SELECT /*+ SeqScan(topics) Parallel(topics 8) */ "topics".* FROM "topics"
|
996
1156
|
def optimizer_hints(*args)
|
997
|
-
check_if_method_has_arguments!(
|
1157
|
+
check_if_method_has_arguments!(__callee__, args)
|
998
1158
|
spawn.optimizer_hints!(*args)
|
999
1159
|
end
|
1000
1160
|
|
@@ -1036,7 +1196,7 @@ module ActiveRecord
|
|
1036
1196
|
#
|
1037
1197
|
# The SQL block comment delimiters, "/*" and "*/", will be added automatically.
|
1038
1198
|
def annotate(*args)
|
1039
|
-
check_if_method_has_arguments!(
|
1199
|
+
check_if_method_has_arguments!(__callee__, args)
|
1040
1200
|
spawn.annotate!(*args)
|
1041
1201
|
end
|
1042
1202
|
|
@@ -1054,6 +1214,47 @@ module ActiveRecord
|
|
1054
1214
|
self
|
1055
1215
|
end
|
1056
1216
|
|
1217
|
+
# Excludes the specified record (or collection of records) from the resulting
|
1218
|
+
# relation. For example:
|
1219
|
+
#
|
1220
|
+
# Post.excluding(post)
|
1221
|
+
# # SELECT "posts".* FROM "posts" WHERE "posts"."id" != 1
|
1222
|
+
#
|
1223
|
+
# Post.excluding(post_one, post_two)
|
1224
|
+
# # SELECT "posts".* FROM "posts" WHERE "posts"."id" NOT IN (1, 2)
|
1225
|
+
#
|
1226
|
+
# This can also be called on associations. As with the above example, either
|
1227
|
+
# a single record of collection thereof may be specified:
|
1228
|
+
#
|
1229
|
+
# post = Post.find(1)
|
1230
|
+
# comment = Comment.find(2)
|
1231
|
+
# post.comments.excluding(comment)
|
1232
|
+
# # SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 AND "comments"."id" != 2
|
1233
|
+
#
|
1234
|
+
# This is short-hand for <tt>.where.not(id: post.id)</tt> and <tt>.where.not(id: [post_one.id, post_two.id])</tt>.
|
1235
|
+
#
|
1236
|
+
# An <tt>ArgumentError</tt> will be raised if either no records are
|
1237
|
+
# specified, or if any of the records in the collection (if a collection
|
1238
|
+
# is passed in) are not instances of the same model that the relation is
|
1239
|
+
# scoping.
|
1240
|
+
def excluding(*records)
|
1241
|
+
records.flatten!(1)
|
1242
|
+
records.compact!
|
1243
|
+
|
1244
|
+
unless records.all?(klass)
|
1245
|
+
raise ArgumentError, "You must only pass a single or collection of #{klass.name} objects to ##{__callee__}."
|
1246
|
+
end
|
1247
|
+
|
1248
|
+
spawn.excluding!(records)
|
1249
|
+
end
|
1250
|
+
alias :without :excluding
|
1251
|
+
|
1252
|
+
def excluding!(records) # :nodoc:
|
1253
|
+
predicates = [ predicate_builder[primary_key, records].invert ]
|
1254
|
+
self.where_clause += Relation::WhereClause.new(predicates)
|
1255
|
+
self
|
1256
|
+
end
|
1257
|
+
|
1057
1258
|
# Returns the Arel object associated with the relation.
|
1058
1259
|
def arel(aliases = nil) # :nodoc:
|
1059
1260
|
@arel ||= build_arel(aliases)
|
@@ -1109,11 +1310,9 @@ module ActiveRecord
|
|
1109
1310
|
nil
|
1110
1311
|
end
|
1111
1312
|
|
1112
|
-
def each_join_dependencies(join_dependencies = build_join_dependencies)
|
1313
|
+
def each_join_dependencies(join_dependencies = build_join_dependencies, &block)
|
1113
1314
|
join_dependencies.each do |join_dependency|
|
1114
|
-
join_dependency.each
|
1115
|
-
yield join
|
1116
|
-
end
|
1315
|
+
join_dependency.each(&block)
|
1117
1316
|
end
|
1118
1317
|
end
|
1119
1318
|
|
@@ -1155,14 +1354,6 @@ module ActiveRecord
|
|
1155
1354
|
unless annotate_values.empty?
|
1156
1355
|
annotates = annotate_values
|
1157
1356
|
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 6.2.
|
1161
|
-
To migrate to Rails 6.2'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
1357
|
arel.comment(*annotates)
|
1167
1358
|
end
|
1168
1359
|
|
@@ -1170,8 +1361,7 @@ module ActiveRecord
|
|
1170
1361
|
end
|
1171
1362
|
|
1172
1363
|
def build_cast_value(name, value)
|
1173
|
-
|
1174
|
-
Arel::Nodes::BindParam.new(cast_value)
|
1364
|
+
ActiveModel::Attribute.with_cast_value(name, value, Type.default_value)
|
1175
1365
|
end
|
1176
1366
|
|
1177
1367
|
def build_from
|
@@ -1282,7 +1472,7 @@ module ActiveRecord
|
|
1282
1472
|
def build_select(arel)
|
1283
1473
|
if select_values.any?
|
1284
1474
|
arel.project(*arel_columns(select_values))
|
1285
|
-
elsif klass.ignored_columns.any?
|
1475
|
+
elsif klass.ignored_columns.any? || klass.enumerate_columns_in_select_statements
|
1286
1476
|
arel.project(*klass.column_names.map { |field| table[field] })
|
1287
1477
|
else
|
1288
1478
|
arel.project(table[Arel.star])
|
@@ -1423,12 +1613,17 @@ module ActiveRecord
|
|
1423
1613
|
order_args.map! do |arg|
|
1424
1614
|
klass.sanitize_sql_for_order(arg)
|
1425
1615
|
end
|
1426
|
-
order_args.flatten!
|
1427
|
-
order_args.compact_blank!
|
1428
1616
|
end
|
1429
1617
|
|
1430
1618
|
def column_references(order_args)
|
1431
|
-
references = order_args.
|
1619
|
+
references = order_args.flat_map do |arg|
|
1620
|
+
case arg
|
1621
|
+
when String, Symbol
|
1622
|
+
arg
|
1623
|
+
when Hash
|
1624
|
+
arg.keys
|
1625
|
+
end
|
1626
|
+
end
|
1432
1627
|
references.map! { |arg| arg =~ /^\W?(\w+)\W?\./ && $1 }.compact!
|
1433
1628
|
references
|
1434
1629
|
end
|
@@ -1476,19 +1671,19 @@ module ActiveRecord
|
|
1476
1671
|
# Post.references() # raises an error
|
1477
1672
|
# Post.references([]) # does not raise an error
|
1478
1673
|
#
|
1479
|
-
# This particular method should be called with a method_name and the args
|
1674
|
+
# This particular method should be called with a method_name (__callee__) and the args
|
1480
1675
|
# passed into that method as an input. For example:
|
1481
1676
|
#
|
1482
1677
|
# def references(*args)
|
1483
|
-
# check_if_method_has_arguments!(
|
1678
|
+
# check_if_method_has_arguments!(__callee__, args)
|
1484
1679
|
# ...
|
1485
1680
|
# end
|
1486
1681
|
def check_if_method_has_arguments!(method_name, args, message = nil)
|
1487
1682
|
if args.blank?
|
1488
1683
|
raise ArgumentError, message || "The method .#{method_name}() must contain arguments."
|
1489
|
-
elsif block_given?
|
1490
|
-
yield args
|
1491
1684
|
else
|
1685
|
+
yield args if block_given?
|
1686
|
+
|
1492
1687
|
args.flatten!
|
1493
1688
|
args.compact_blank!
|
1494
1689
|
end
|
@@ -1512,11 +1707,4 @@ module ActiveRecord
|
|
1512
1707
|
end
|
1513
1708
|
end
|
1514
1709
|
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
1710
|
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.
|
@@ -76,6 +76,11 @@ module ActiveRecord
|
|
76
76
|
other.is_a?(WhereClause) &&
|
77
77
|
predicates == other.predicates
|
78
78
|
end
|
79
|
+
alias :eql? :==
|
80
|
+
|
81
|
+
def hash
|
82
|
+
[self.class, predicates].hash
|
83
|
+
end
|
79
84
|
|
80
85
|
def invert
|
81
86
|
if predicates.size == 1
|
@@ -158,21 +163,8 @@ module ActiveRecord
|
|
158
163
|
attr = extract_attribute(node) || begin
|
159
164
|
node.left if equality_node?(node) && node.left.is_a?(Arel::Predications)
|
160
165
|
end
|
161
|
-
|
162
|
-
|
163
|
-
ref = referenced_columns[attr]
|
164
|
-
next false unless ref
|
165
|
-
|
166
|
-
if equality_node?(node) && equality_node?(ref) || node == ref
|
167
|
-
true
|
168
|
-
else
|
169
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
170
|
-
Merging (#{node.to_sql}) and (#{ref.to_sql}) no longer maintain
|
171
|
-
both conditions, and will be replaced by the latter in Rails 6.2.
|
172
|
-
To migrate to Rails 6.2's behavior, use `relation.merge(other, rewhere: true)`.
|
173
|
-
MSG
|
174
|
-
false
|
175
|
-
end
|
166
|
+
|
167
|
+
attr && referenced_columns[attr]
|
176
168
|
end
|
177
169
|
end
|
178
170
|
|
@@ -227,11 +219,10 @@ module ActiveRecord
|
|
227
219
|
end
|
228
220
|
|
229
221
|
def extract_node_value(node)
|
230
|
-
|
231
|
-
when Array
|
232
|
-
node.map { |v| extract_node_value(v) }
|
233
|
-
when Arel::Nodes::BindParam, Arel::Nodes::Casted, Arel::Nodes::Quoted
|
222
|
+
if node.respond_to?(:value_before_type_cast)
|
234
223
|
node.value_before_type_cast
|
224
|
+
elsif Array === node
|
225
|
+
node.map { |v| extract_node_value(v) }
|
235
226
|
end
|
236
227
|
end
|
237
228
|
end
|