activerecord 6.1.7 → 7.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2030 -1020
- data/MIT-LICENSE +1 -1
- data/README.rdoc +18 -18
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +1 -11
- data/lib/active_record/associations/association.rb +51 -19
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +28 -9
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +40 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
- 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 +6 -2
- data/lib/active_record/associations/collection_association.rb +39 -35
- data/lib/active_record/associations/collection_proxy.rb +30 -15
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +28 -18
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
- data/lib/active_record/associations/join_dependency.rb +28 -20
- data/lib/active_record/associations/preloader/association.rb +210 -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 +50 -14
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +9 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +446 -306
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +1 -3
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +78 -26
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +27 -12
- data/lib/active_record/attribute_methods/serialization.rb +194 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +161 -40
- data/lib/active_record/attributes.rb +27 -38
- data/lib/active_record/autosave_association.rb +65 -31
- data/lib/active_record/base.rb +25 -2
- data/lib/active_record/callbacks.rb +18 -34
- 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 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
- data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
- data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
- data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
- data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
- data/lib/active_record/connection_adapters/pool_config.rb +20 -11
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- 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/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- 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 +89 -56
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
- data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
- data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
- 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 +258 -0
- data/lib/active_record/connection_adapters.rb +9 -6
- data/lib/active_record/connection_handling.rb +108 -137
- data/lib/active_record/core.rb +242 -233
- data/lib/active_record/counter_cache.rb +52 -27
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
- data/lib/active_record/database_configurations/database_config.rb +21 -12
- data/lib/active_record/database_configurations/hash_config.rb +88 -16
- data/lib/active_record/database_configurations/url_config.rb +18 -12
- data/lib/active_record/database_configurations.rb +95 -59
- data/lib/active_record/delegated_type.rb +66 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- 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/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -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 +157 -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 +53 -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 +92 -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 +100 -0
- data/lib/active_record/encryption.rb +58 -0
- data/lib/active_record/enum.rb +154 -63
- data/lib/active_record/errors.rb +172 -15
- data/lib/active_record/explain.rb +23 -3
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- 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 +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +147 -86
- data/lib/active_record/future_result.rb +174 -0
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +81 -29
- data/lib/active_record/insert_all.rb +135 -22
- data/lib/active_record/integration.rb +11 -10
- data/lib/active_record/internal_metadata.rb +119 -33
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +37 -22
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +52 -19
- data/lib/active_record/marshalling.rb +59 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +112 -14
- data/lib/active_record/migration/compatibility.rb +233 -46
- 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/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +361 -173
- data/lib/active_record/model_schema.rb +125 -101
- data/lib/active_record/nested_attributes.rb +50 -20
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +167 -0
- data/lib/active_record/persistence.rb +409 -88
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +4 -22
- data/lib/active_record/query_logs.rb +174 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +29 -6
- data/lib/active_record/railtie.rb +220 -44
- data/lib/active_record/railties/controller_runtime.rb +15 -10
- data/lib/active_record/railties/databases.rake +188 -252
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +248 -81
- data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
- data/lib/active_record/relation/batches.rb +192 -63
- data/lib/active_record/relation/calculations.rb +246 -90
- data/lib/active_record/relation/delegation.rb +28 -14
- data/lib/active_record/relation/finder_methods.rb +108 -51
- data/lib/active_record/relation/merger.rb +22 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +27 -20
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +670 -129
- data/lib/active_record/relation/record_fetch_warning.rb +7 -9
- data/lib/active_record/relation/spawn_methods.rb +20 -3
- data/lib/active_record/relation/where_clause.rb +10 -19
- data/lib/active_record/relation.rb +287 -120
- data/lib/active_record/result.rb +37 -11
- data/lib/active_record/runtime_registry.rb +32 -13
- data/lib/active_record/sanitization.rb +65 -20
- data/lib/active_record/schema.rb +36 -22
- data/lib/active_record/schema_dumper.rb +73 -24
- data/lib/active_record/schema_migration.rb +68 -33
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +10 -8
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +16 -3
- data/lib/active_record/tasks/database_tasks.rb +251 -140
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +117 -96
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +113 -0
- data/lib/active_record/touch_later.rb +11 -6
- data/lib/active_record/transactions.rb +48 -27
- data/lib/active_record/translation.rb +3 -3
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -5
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +4 -4
- 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 +51 -6
- data/lib/active_record/validations.rb +8 -4
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +335 -32
- 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/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- 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/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/node.rb +111 -2
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +6 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +5 -0
- data/lib/arel/predications.rb +13 -3
- data/lib/arel/select_manager.rb +10 -4
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +5 -13
- data/lib/arel/update_manager.rb +18 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +16 -3
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +141 -20
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +18 -3
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- 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
- 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 +96 -16
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -3,7 +3,49 @@
|
|
3
3
|
require "active_support/core_ext/enumerable"
|
4
4
|
|
5
5
|
module ActiveRecord
|
6
|
+
# = Active Record \Calculations
|
6
7
|
module Calculations
|
8
|
+
class ColumnAliasTracker # :nodoc:
|
9
|
+
def initialize(connection)
|
10
|
+
@connection = connection
|
11
|
+
@aliases = Hash.new(0)
|
12
|
+
end
|
13
|
+
|
14
|
+
def alias_for(field)
|
15
|
+
aliased_name = column_alias_for(field)
|
16
|
+
|
17
|
+
if @aliases[aliased_name] == 0
|
18
|
+
@aliases[aliased_name] = 1
|
19
|
+
aliased_name
|
20
|
+
else
|
21
|
+
# Update the count
|
22
|
+
count = @aliases[aliased_name] += 1
|
23
|
+
"#{truncate(aliased_name)}_#{count}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
# Converts the given field to the value that the database adapter returns as
|
29
|
+
# a usable column name:
|
30
|
+
#
|
31
|
+
# column_alias_for("users.id") # => "users_id"
|
32
|
+
# column_alias_for("sum(id)") # => "sum_id"
|
33
|
+
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
34
|
+
# column_alias_for("count(*)") # => "count_all"
|
35
|
+
def column_alias_for(field)
|
36
|
+
column_alias = +field
|
37
|
+
column_alias.gsub!(/\*/, "all")
|
38
|
+
column_alias.gsub!(/\W+/, " ")
|
39
|
+
column_alias.strip!
|
40
|
+
column_alias.gsub!(/ +/, "_")
|
41
|
+
@connection.table_alias_for(column_alias)
|
42
|
+
end
|
43
|
+
|
44
|
+
def truncate(name)
|
45
|
+
name.slice(0, @connection.table_alias_length - 2)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
7
49
|
# Count the records.
|
8
50
|
#
|
9
51
|
# Person.count
|
@@ -30,8 +72,7 @@ module ActiveRecord
|
|
30
72
|
# of each key would be the #count.
|
31
73
|
#
|
32
74
|
# Article.group(:status, :category).count
|
33
|
-
# # => {["draft", "business"]=>10, ["draft", "technology"]=>4,
|
34
|
-
# ["published", "business"]=>0, ["published", "technology"]=>2}
|
75
|
+
# # => {["draft", "business"]=>10, ["draft", "technology"]=>4, ["published", "technology"]=>2}
|
35
76
|
#
|
36
77
|
# If #count is used with {Relation#select}[rdoc-ref:QueryMethods#select], it will count the selected columns:
|
37
78
|
#
|
@@ -40,6 +81,16 @@ module ActiveRecord
|
|
40
81
|
#
|
41
82
|
# Note: not all valid {Relation#select}[rdoc-ref:QueryMethods#select] expressions are valid #count expressions. The specifics differ
|
42
83
|
# between databases. In invalid cases, an error from the database is thrown.
|
84
|
+
#
|
85
|
+
# When given a block, loads all records in the relation, if the relation
|
86
|
+
# hasn't been loaded yet. Calls the block with each record in the relation.
|
87
|
+
# Returns the number of records for which the block returns a truthy value.
|
88
|
+
#
|
89
|
+
# Person.count { |person| person.age > 21 }
|
90
|
+
# # => counts the number of people older that 21
|
91
|
+
#
|
92
|
+
# Note: If there are a lot of records in the relation, loading all records
|
93
|
+
# could result in performance issues.
|
43
94
|
def count(column_name = nil)
|
44
95
|
if block_given?
|
45
96
|
unless column_name.nil?
|
@@ -52,6 +103,12 @@ module ActiveRecord
|
|
52
103
|
end
|
53
104
|
end
|
54
105
|
|
106
|
+
# Same as #count, but performs the query asynchronously and returns an
|
107
|
+
# ActiveRecord::Promise.
|
108
|
+
def async_count(column_name = nil)
|
109
|
+
async.count(column_name)
|
110
|
+
end
|
111
|
+
|
55
112
|
# Calculates the average value on a given column. Returns +nil+ if there's
|
56
113
|
# no row. See #calculate for examples with options.
|
57
114
|
#
|
@@ -60,6 +117,12 @@ module ActiveRecord
|
|
60
117
|
calculate(:average, column_name)
|
61
118
|
end
|
62
119
|
|
120
|
+
# Same as #average, but performs the query asynchronously and returns an
|
121
|
+
# ActiveRecord::Promise.
|
122
|
+
def async_average(column_name)
|
123
|
+
async.average(column_name)
|
124
|
+
end
|
125
|
+
|
63
126
|
# Calculates the minimum value on a given column. The value is returned
|
64
127
|
# with the same data type of the column, or +nil+ if there's no row. See
|
65
128
|
# #calculate for examples with options.
|
@@ -69,6 +132,12 @@ module ActiveRecord
|
|
69
132
|
calculate(:minimum, column_name)
|
70
133
|
end
|
71
134
|
|
135
|
+
# Same as #minimum, but performs the query asynchronously and returns an
|
136
|
+
# ActiveRecord::Promise.
|
137
|
+
def async_minimum(column_name)
|
138
|
+
async.minimum(column_name)
|
139
|
+
end
|
140
|
+
|
72
141
|
# Calculates the maximum value on a given column. The value is returned
|
73
142
|
# with the same data type of the column, or +nil+ if there's no row. See
|
74
143
|
# #calculate for examples with options.
|
@@ -78,23 +147,42 @@ module ActiveRecord
|
|
78
147
|
calculate(:maximum, column_name)
|
79
148
|
end
|
80
149
|
|
150
|
+
# Same as #maximum, but performs the query asynchronously and returns an
|
151
|
+
# ActiveRecord::Promise.
|
152
|
+
def async_maximum(column_name)
|
153
|
+
async.maximum(column_name)
|
154
|
+
end
|
155
|
+
|
81
156
|
# Calculates the sum of values on a given column. The value is returned
|
82
157
|
# with the same data type of the column, +0+ if there's no row. See
|
83
158
|
# #calculate for examples with options.
|
84
159
|
#
|
85
160
|
# Person.sum(:age) # => 4562
|
86
|
-
|
161
|
+
#
|
162
|
+
# When given a block, loads all records in the relation, if the relation
|
163
|
+
# hasn't been loaded yet. Calls the block with each record in the relation.
|
164
|
+
# Returns the sum of +initial_value_or_column+ and the block return
|
165
|
+
# values:
|
166
|
+
#
|
167
|
+
# Person.sum { |person| person.age } # => 4562
|
168
|
+
# Person.sum(1000) { |person| person.age } # => 5562
|
169
|
+
#
|
170
|
+
# Note: If there are a lot of records in the relation, loading all records
|
171
|
+
# could result in performance issues.
|
172
|
+
def sum(initial_value_or_column = 0, &block)
|
87
173
|
if block_given?
|
88
|
-
|
89
|
-
raise ArgumentError, "Column name argument is not supported when a block is passed."
|
90
|
-
end
|
91
|
-
|
92
|
-
super()
|
174
|
+
map(&block).sum(initial_value_or_column)
|
93
175
|
else
|
94
|
-
calculate(:sum,
|
176
|
+
calculate(:sum, initial_value_or_column)
|
95
177
|
end
|
96
178
|
end
|
97
179
|
|
180
|
+
# Same as #sum, but performs the query asynchronously and returns an
|
181
|
+
# ActiveRecord::Promise.
|
182
|
+
def async_sum(identity_or_column = nil)
|
183
|
+
async.sum(identity_or_column)
|
184
|
+
end
|
185
|
+
|
98
186
|
# This calculates aggregate values in the given column. Methods for #count, #sum, #average,
|
99
187
|
# #minimum, and #maximum have been added as shortcuts.
|
100
188
|
#
|
@@ -127,10 +215,23 @@ module ActiveRecord
|
|
127
215
|
# ...
|
128
216
|
# end
|
129
217
|
def calculate(operation, column_name)
|
218
|
+
operation = operation.to_s.downcase
|
219
|
+
|
220
|
+
if @none
|
221
|
+
case operation
|
222
|
+
when "count", "sum"
|
223
|
+
result = group_values.any? ? Hash.new : 0
|
224
|
+
return @async ? Promise::Complete.new(result) : result
|
225
|
+
when "average", "minimum", "maximum"
|
226
|
+
result = group_values.any? ? Hash.new : nil
|
227
|
+
return @async ? Promise::Complete.new(result) : result
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
130
231
|
if has_include?(column_name)
|
131
232
|
relation = apply_join_dependency
|
132
233
|
|
133
|
-
if operation
|
234
|
+
if operation == "count"
|
134
235
|
unless distinct_value || distinct_select?(column_name || select_for_count)
|
135
236
|
relation.distinct!
|
136
237
|
relation.select_values = [ klass.primary_key || table[Arel.star] ]
|
@@ -146,7 +247,7 @@ module ActiveRecord
|
|
146
247
|
end
|
147
248
|
|
148
249
|
# Use #pluck as a shortcut to select one or more attributes without
|
149
|
-
# loading
|
250
|
+
# loading an entire record object per row.
|
150
251
|
#
|
151
252
|
# Person.pluck(:name)
|
152
253
|
#
|
@@ -179,31 +280,51 @@ module ActiveRecord
|
|
179
280
|
# # => ['0', '27761', '173']
|
180
281
|
#
|
181
282
|
# See also #ids.
|
182
|
-
#
|
183
283
|
def pluck(*column_names)
|
284
|
+
if @none
|
285
|
+
if @async
|
286
|
+
return Promise::Complete.new([])
|
287
|
+
else
|
288
|
+
return []
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
184
292
|
if loaded? && all_attributes?(column_names)
|
185
|
-
|
293
|
+
result = records.pluck(*column_names)
|
294
|
+
if @async
|
295
|
+
return Promise::Complete.new(result)
|
296
|
+
else
|
297
|
+
return result
|
298
|
+
end
|
186
299
|
end
|
187
300
|
|
188
301
|
if has_include?(column_names.first)
|
189
302
|
relation = apply_join_dependency
|
190
303
|
relation.pluck(*column_names)
|
191
304
|
else
|
192
|
-
klass.disallow_raw_sql!(column_names)
|
305
|
+
klass.disallow_raw_sql!(column_names.flatten)
|
193
306
|
columns = arel_columns(column_names)
|
194
307
|
relation = spawn
|
195
308
|
relation.select_values = columns
|
196
309
|
result = skip_query_cache_if_necessary do
|
197
310
|
if where_clause.contradiction?
|
198
|
-
ActiveRecord::Result.
|
311
|
+
ActiveRecord::Result.empty(async: @async)
|
199
312
|
else
|
200
|
-
klass.connection.select_all(relation.arel,
|
313
|
+
klass.connection.select_all(relation.arel, "#{klass.name} Pluck", async: @async)
|
201
314
|
end
|
202
315
|
end
|
203
|
-
|
316
|
+
result.then do |result|
|
317
|
+
type_cast_pluck_values(result, columns)
|
318
|
+
end
|
204
319
|
end
|
205
320
|
end
|
206
321
|
|
322
|
+
# Same as #pluck, but performs the query asynchronously and returns an
|
323
|
+
# ActiveRecord::Promise.
|
324
|
+
def async_pluck(*column_names)
|
325
|
+
async.pluck(*column_names)
|
326
|
+
end
|
327
|
+
|
207
328
|
# Pick the value(s) from the named column(s) in the current relation.
|
208
329
|
# This is short-hand for <tt>relation.limit(1).pluck(*column_names).first</tt>, and is primarily useful
|
209
330
|
# when you have a relation that's already narrowed down to a single row.
|
@@ -220,18 +341,61 @@ module ActiveRecord
|
|
220
341
|
# # => [ 'David', 'david@loudthinking.com' ]
|
221
342
|
def pick(*column_names)
|
222
343
|
if loaded? && all_attributes?(column_names)
|
223
|
-
|
344
|
+
result = records.pick(*column_names)
|
345
|
+
return @async ? Promise::Complete.new(result) : result
|
224
346
|
end
|
225
347
|
|
226
|
-
limit(1).pluck(*column_names).first
|
348
|
+
limit(1).pluck(*column_names).then(&:first)
|
227
349
|
end
|
228
350
|
|
229
|
-
#
|
351
|
+
# Same as #pick, but performs the query asynchronously and returns an
|
352
|
+
# ActiveRecord::Promise.
|
353
|
+
def async_pick(*column_names)
|
354
|
+
async.pick(*column_names)
|
355
|
+
end
|
356
|
+
|
357
|
+
# Returns the base model's ID's for the relation using the table's primary key
|
230
358
|
#
|
231
359
|
# Person.ids # SELECT people.id FROM people
|
232
|
-
# Person.joins(:companies).ids # SELECT people.id FROM people INNER JOIN companies ON companies.
|
360
|
+
# Person.joins(:companies).ids # SELECT people.id FROM people INNER JOIN companies ON companies.id = people.company_id
|
233
361
|
def ids
|
234
|
-
|
362
|
+
primary_key_array = Array(primary_key)
|
363
|
+
|
364
|
+
if loaded?
|
365
|
+
result = records.map do |record|
|
366
|
+
if primary_key_array.one?
|
367
|
+
record._read_attribute(primary_key_array.first)
|
368
|
+
else
|
369
|
+
primary_key_array.map { |column| record._read_attribute(column) }
|
370
|
+
end
|
371
|
+
end
|
372
|
+
return @async ? Promise::Complete.new(result) : result
|
373
|
+
end
|
374
|
+
|
375
|
+
if has_include?(primary_key)
|
376
|
+
relation = apply_join_dependency.group(*primary_key_array)
|
377
|
+
return relation.ids
|
378
|
+
end
|
379
|
+
|
380
|
+
columns = arel_columns(primary_key_array)
|
381
|
+
relation = spawn
|
382
|
+
relation.select_values = columns
|
383
|
+
|
384
|
+
result = if relation.where_clause.contradiction?
|
385
|
+
ActiveRecord::Result.empty
|
386
|
+
else
|
387
|
+
skip_query_cache_if_necessary do
|
388
|
+
klass.connection.select_all(relation, "#{klass.name} Ids", async: @async)
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
result.then { |result| type_cast_pluck_values(result, columns) }
|
393
|
+
end
|
394
|
+
|
395
|
+
# Same as #ids, but performs the query asynchronously and returns an
|
396
|
+
# ActiveRecord::Promise.
|
397
|
+
def async_ids
|
398
|
+
async.ids
|
235
399
|
end
|
236
400
|
|
237
401
|
private
|
@@ -286,11 +450,12 @@ module ActiveRecord
|
|
286
450
|
operation == "count" ? column.count(distinct) : column.public_send(operation)
|
287
451
|
end
|
288
452
|
|
289
|
-
def execute_simple_calculation(operation, column_name, distinct)
|
453
|
+
def execute_simple_calculation(operation, column_name, distinct) # :nodoc:
|
290
454
|
if operation == "count" && (column_name == :all && distinct || has_limit_or_offset?)
|
291
455
|
# Shortcut when limit is zero.
|
292
456
|
return 0 if limit_value == 0
|
293
457
|
|
458
|
+
relation = self
|
294
459
|
query_builder = build_count_subquery(spawn, column_name, distinct)
|
295
460
|
else
|
296
461
|
# PostgreSQL doesn't like ORDER BY when there are no GROUP BY
|
@@ -305,29 +470,29 @@ module ActiveRecord
|
|
305
470
|
query_builder = relation.arel
|
306
471
|
end
|
307
472
|
|
308
|
-
|
473
|
+
query_result = if relation.where_clause.contradiction?
|
474
|
+
ActiveRecord::Result.empty
|
475
|
+
else
|
476
|
+
skip_query_cache_if_necessary do
|
477
|
+
@klass.connection.select_all(query_builder, "#{@klass.name} #{operation.capitalize}", async: @async)
|
478
|
+
end
|
479
|
+
end
|
309
480
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
481
|
+
query_result.then do |result|
|
482
|
+
if operation != "count"
|
483
|
+
type = column.try(:type_caster) ||
|
484
|
+
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
485
|
+
type = type.subtype if Enum::EnumType === type
|
486
|
+
end
|
487
|
+
|
488
|
+
type_cast_calculated_value(result.cast_values.first, operation, type)
|
315
489
|
end
|
316
490
|
end
|
317
491
|
|
318
|
-
def execute_grouped_calculation(operation, column_name, distinct)
|
492
|
+
def execute_grouped_calculation(operation, column_name, distinct) # :nodoc:
|
319
493
|
group_fields = group_values
|
320
494
|
group_fields = group_fields.uniq if group_fields.size > 1
|
321
495
|
|
322
|
-
unless group_fields == group_values
|
323
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
324
|
-
`#{operation}` with group by duplicated fields does no longer affect to result in Rails 7.0.
|
325
|
-
To migrate to Rails 7.0's behavior, use `uniq!(:group)` to deduplicate group fields
|
326
|
-
(`#{klass.name&.tableize || klass.table_name}.uniq!(:group).#{operation}(#{column_name.inspect})`).
|
327
|
-
MSG
|
328
|
-
group_fields = group_values
|
329
|
-
end
|
330
|
-
|
331
496
|
if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
|
332
497
|
association = klass._reflect_on_association(group_fields.first)
|
333
498
|
associated = association && association.belongs_to? # only count belongs_to associations
|
@@ -335,21 +500,24 @@ module ActiveRecord
|
|
335
500
|
end
|
336
501
|
group_fields = arel_columns(group_fields)
|
337
502
|
|
503
|
+
column_alias_tracker = ColumnAliasTracker.new(connection)
|
504
|
+
|
338
505
|
group_aliases = group_fields.map { |field|
|
339
506
|
field = connection.visitor.compile(field) if Arel.arel_node?(field)
|
340
|
-
|
507
|
+
column_alias_tracker.alias_for(field.to_s.downcase)
|
341
508
|
}
|
342
509
|
group_columns = group_aliases.zip(group_fields)
|
343
510
|
|
344
511
|
column = aggregate_column(column_name)
|
345
|
-
column_alias =
|
512
|
+
column_alias = column_alias_tracker.alias_for("#{operation} #{column_name.to_s.downcase}")
|
346
513
|
select_value = operation_over_aggregate_column(column, operation, distinct)
|
347
|
-
select_value.as(column_alias)
|
514
|
+
select_value.as(connection.quote_column_name(column_alias))
|
348
515
|
|
349
516
|
select_values = [select_value]
|
350
517
|
select_values += self.select_values unless having_clause.empty?
|
351
518
|
|
352
519
|
select_values.concat group_columns.map { |aliaz, field|
|
520
|
+
aliaz = connection.quote_column_name(aliaz)
|
353
521
|
if field.respond_to?(:as)
|
354
522
|
field.as(aliaz)
|
355
523
|
else
|
@@ -361,60 +529,43 @@ module ActiveRecord
|
|
361
529
|
relation.group_values = group_fields
|
362
530
|
relation.select_values = select_values
|
363
531
|
|
364
|
-
|
532
|
+
result = skip_query_cache_if_necessary { @klass.connection.select_all(relation.arel, "#{@klass.name} #{operation.capitalize}", async: @async) }
|
533
|
+
result.then do |calculated_data|
|
534
|
+
if association
|
535
|
+
key_ids = calculated_data.collect { |row| row[group_aliases.first] }
|
536
|
+
key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
|
537
|
+
key_records = key_records.index_by(&:id)
|
538
|
+
end
|
365
539
|
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
540
|
+
key_types = group_columns.each_with_object({}) do |(aliaz, col_name), types|
|
541
|
+
types[aliaz] = col_name.try(:type_caster) ||
|
542
|
+
type_for(col_name) do
|
543
|
+
calculated_data.column_types.fetch(aliaz, Type.default_value)
|
544
|
+
end
|
545
|
+
end
|
371
546
|
|
372
|
-
|
373
|
-
|
374
|
-
|
547
|
+
hash_rows = calculated_data.cast_values(key_types).map! do |row|
|
548
|
+
calculated_data.columns.each_with_object({}).with_index do |(col_name, hash), i|
|
549
|
+
hash[col_name] = row[i]
|
550
|
+
end
|
375
551
|
end
|
376
|
-
end
|
377
552
|
|
378
|
-
|
379
|
-
|
380
|
-
|
553
|
+
if operation != "count"
|
554
|
+
type = column.try(:type_caster) ||
|
555
|
+
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
556
|
+
type = type.subtype if Enum::EnumType === type
|
381
557
|
end
|
382
|
-
end
|
383
558
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
result[key] = type_cast_calculated_value(row[column_alias], operation) do |value|
|
391
|
-
unless type
|
392
|
-
type = column.try(:type_caster) ||
|
393
|
-
lookup_cast_type_from_join_dependencies(column_name.to_s) || Type.default_value
|
394
|
-
type = type.subtype if Enum::EnumType === type
|
395
|
-
end
|
396
|
-
type.deserialize(value)
|
559
|
+
hash_rows.each_with_object({}) do |row, result|
|
560
|
+
key = group_aliases.map { |aliaz| row[aliaz] }
|
561
|
+
key = key.first if key.size == 1
|
562
|
+
key = key_records[key] if associated
|
563
|
+
|
564
|
+
result[key] = type_cast_calculated_value(row[column_alias], operation, type)
|
397
565
|
end
|
398
566
|
end
|
399
567
|
end
|
400
568
|
|
401
|
-
# Converts the given field to the value that the database adapter returns as
|
402
|
-
# a usable column name:
|
403
|
-
#
|
404
|
-
# column_alias_for("users.id") # => "users_id"
|
405
|
-
# column_alias_for("sum(id)") # => "sum_id"
|
406
|
-
# column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
|
407
|
-
# column_alias_for("count(*)") # => "count_all"
|
408
|
-
def column_alias_for(field)
|
409
|
-
column_alias = +field
|
410
|
-
column_alias.gsub!(/\*/, "all")
|
411
|
-
column_alias.gsub!(/\W+/, " ")
|
412
|
-
column_alias.strip!
|
413
|
-
column_alias.gsub!(/ +/, "_")
|
414
|
-
|
415
|
-
connection.table_alias_for(column_alias)
|
416
|
-
end
|
417
|
-
|
418
569
|
def type_for(field, &block)
|
419
570
|
field_name = field.respond_to?(:name) ? field.name.to_s : field.to_s.split(".").last
|
420
571
|
@klass.type_for_attribute(field_name, &block)
|
@@ -445,16 +596,21 @@ module ActiveRecord
|
|
445
596
|
result.cast_values(cast_types)
|
446
597
|
end
|
447
598
|
|
448
|
-
def type_cast_calculated_value(value, operation)
|
599
|
+
def type_cast_calculated_value(value, operation, type)
|
449
600
|
case operation
|
450
601
|
when "count"
|
451
602
|
value.to_i
|
452
603
|
when "sum"
|
453
|
-
|
604
|
+
type.deserialize(value || 0)
|
454
605
|
when "average"
|
455
|
-
|
606
|
+
case type.type
|
607
|
+
when :integer, :decimal
|
608
|
+
value&.to_d
|
609
|
+
else
|
610
|
+
type.deserialize(value)
|
611
|
+
end
|
456
612
|
else # "minimum", "maximum"
|
457
|
-
|
613
|
+
type.deserialize(value)
|
458
614
|
end
|
459
615
|
end
|
460
616
|
|
@@ -5,6 +5,23 @@ require "active_support/core_ext/module/delegation"
|
|
5
5
|
|
6
6
|
module ActiveRecord
|
7
7
|
module Delegation # :nodoc:
|
8
|
+
class << self
|
9
|
+
def delegated_classes
|
10
|
+
[
|
11
|
+
ActiveRecord::Relation,
|
12
|
+
ActiveRecord::Associations::CollectionProxy,
|
13
|
+
ActiveRecord::AssociationRelation,
|
14
|
+
ActiveRecord::DisableJoinsAssociationRelation,
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
18
|
+
def uncacheable_methods
|
19
|
+
@uncacheable_methods ||= (
|
20
|
+
delegated_classes.flat_map(&:public_instance_methods) - ActiveRecord::Relation.public_instance_methods
|
21
|
+
).to_set.freeze
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
8
25
|
module DelegateCache # :nodoc:
|
9
26
|
def relation_delegate_class(klass)
|
10
27
|
@relation_delegate_cache[klass]
|
@@ -12,11 +29,7 @@ module ActiveRecord
|
|
12
29
|
|
13
30
|
def initialize_relation_delegate_cache
|
14
31
|
@relation_delegate_cache = cache = {}
|
15
|
-
|
16
|
-
ActiveRecord::Relation,
|
17
|
-
ActiveRecord::Associations::CollectionProxy,
|
18
|
-
ActiveRecord::AssociationRelation
|
19
|
-
].each do |klass|
|
32
|
+
Delegation.delegated_classes.each do |klass|
|
20
33
|
delegate = Class.new(klass) {
|
21
34
|
include ClassSpecificRelation
|
22
35
|
}
|
@@ -61,17 +74,16 @@ module ActiveRecord
|
|
61
74
|
return if method_defined?(method)
|
62
75
|
|
63
76
|
if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !DELEGATION_RESERVED_METHOD_NAMES.include?(method.to_s)
|
64
|
-
definition = RUBY_VERSION >= "2.7" ? "..." : "*args, &block"
|
65
77
|
module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
66
|
-
def #{method}(
|
67
|
-
scoping { klass.#{method}(
|
78
|
+
def #{method}(...)
|
79
|
+
scoping { klass.#{method}(...) }
|
68
80
|
end
|
69
81
|
RUBY
|
70
82
|
else
|
71
83
|
define_method(method) do |*args, &block|
|
72
84
|
scoping { klass.public_send(method, *args, &block) }
|
73
85
|
end
|
74
|
-
ruby2_keywords(method)
|
86
|
+
ruby2_keywords(method)
|
75
87
|
end
|
76
88
|
end
|
77
89
|
end
|
@@ -85,12 +97,12 @@ module ActiveRecord
|
|
85
97
|
# may vary depending on the klass of a relation, so we create a subclass of Relation
|
86
98
|
# for each different klass, and the delegations are compiled into that subclass only.
|
87
99
|
|
88
|
-
delegate :to_xml, :encode_with, :length, :each, :join,
|
100
|
+
delegate :to_xml, :encode_with, :length, :each, :join, :intersect?,
|
89
101
|
:[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
|
90
|
-
:to_sentence, :to_formatted_s, :as_json,
|
102
|
+
:to_sentence, :to_fs, :to_formatted_s, :as_json,
|
91
103
|
:shuffle, :split, :slice, :index, :rindex, to: :records
|
92
104
|
|
93
|
-
delegate :primary_key, :connection, to: :klass
|
105
|
+
delegate :primary_key, :connection, :transaction, to: :klass
|
94
106
|
|
95
107
|
module ClassSpecificRelation # :nodoc:
|
96
108
|
extend ActiveSupport::Concern
|
@@ -104,13 +116,15 @@ module ActiveRecord
|
|
104
116
|
private
|
105
117
|
def method_missing(method, *args, &block)
|
106
118
|
if @klass.respond_to?(method)
|
107
|
-
|
119
|
+
unless Delegation.uncacheable_methods.include?(method)
|
120
|
+
@klass.generate_relation_method(method)
|
121
|
+
end
|
108
122
|
scoping { @klass.public_send(method, *args, &block) }
|
109
123
|
else
|
110
124
|
super
|
111
125
|
end
|
112
126
|
end
|
113
|
-
ruby2_keywords(:method_missing)
|
127
|
+
ruby2_keywords(:method_missing)
|
114
128
|
end
|
115
129
|
|
116
130
|
module ClassMethods # :nodoc:
|