activerecord 6.1.7.4 → 7.0.6
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 +1449 -1014
- data/README.rdoc +3 -3
- 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 +14 -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 +50 -14
- data/lib/active_record/associations/preloader.rb +39 -113
- data/lib/active_record/associations/singular_association.rb +15 -7
- data/lib/active_record/associations/through_association.rb +3 -3
- data/lib/active_record/associations.rb +138 -100
- 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 +8 -6
- data/lib/active_record/attribute_methods/serialization.rb +57 -19
- 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 +19 -22
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +17 -28
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +14 -16
- data/lib/active_record/coders/yaml_column.rb +4 -8
- 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 +52 -23
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +82 -25
- data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
- data/lib/active_record/connection_adapters/abstract_adapter.rb +153 -74
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -84
- 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 +45 -21
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
- 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 +19 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -17
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- 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 +71 -71
- 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 +40 -21
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -106
- 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 +97 -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 +123 -148
- 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/explain_subscriber.rb +1 -1
- 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 +5 -5
- 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 +36 -21
- 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 +8 -9
- data/lib/active_record/migration/compatibility.rb +91 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +115 -84
- 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 +149 -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 +80 -49
- 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 +92 -60
- 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/association_query_value.rb +20 -1
- data/lib/active_record/relation/predicate_builder.rb +2 -6
- data/lib/active_record/relation/query_attribute.rb +5 -11
- data/lib/active_record/relation/query_methods.rb +285 -68
- 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 +23 -11
- 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 +29 -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 +2 -2
- data/lib/active_record/suppressor.rb +11 -15
- data/lib/active_record/table_metadata.rb +5 -1
- 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 +9 -6
- 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 +5 -5
- 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 +225 -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 +58 -14
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/module/attribute_accessors_per_thread"
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
# = Active Record Query Logs
|
7
|
+
#
|
8
|
+
# Automatically tag SQL queries with runtime information.
|
9
|
+
#
|
10
|
+
# Default tags available for use:
|
11
|
+
#
|
12
|
+
# * +application+
|
13
|
+
# * +pid+
|
14
|
+
# * +socket+
|
15
|
+
# * +db_host+
|
16
|
+
# * +database+
|
17
|
+
#
|
18
|
+
# _Action Controller and Active Job tags are also defined when used in Rails:_
|
19
|
+
#
|
20
|
+
# * +controller+
|
21
|
+
# * +action+
|
22
|
+
# * +job+
|
23
|
+
#
|
24
|
+
# The tags used in a query can be configured directly:
|
25
|
+
#
|
26
|
+
# ActiveRecord::QueryLogs.tags = [ :application, :controller, :action, :job ]
|
27
|
+
#
|
28
|
+
# or via Rails configuration:
|
29
|
+
#
|
30
|
+
# config.active_record.query_log_tags = [ :application, :controller, :action, :job ]
|
31
|
+
#
|
32
|
+
# To add new comment tags, add a hash to the tags array containing the keys and values you
|
33
|
+
# want to add to the comment. Dynamic content can be created by setting a proc or lambda value in a hash,
|
34
|
+
# and can reference any value stored in the +context+ object.
|
35
|
+
#
|
36
|
+
# Escaping is performed on the string returned, however untrusted user input should not be used.
|
37
|
+
#
|
38
|
+
# Example:
|
39
|
+
#
|
40
|
+
# tags = [
|
41
|
+
# :application,
|
42
|
+
# {
|
43
|
+
# custom_tag: ->(context) { context[:controller]&.controller_name },
|
44
|
+
# custom_value: -> { Custom.value },
|
45
|
+
# }
|
46
|
+
# ]
|
47
|
+
# ActiveRecord::QueryLogs.tags = tags
|
48
|
+
#
|
49
|
+
# The QueryLogs +context+ can be manipulated via the +ActiveSupport::ExecutionContext.set+ method.
|
50
|
+
#
|
51
|
+
# Temporary updates limited to the execution of a block:
|
52
|
+
#
|
53
|
+
# ActiveSupport::ExecutionContext.set(foo: Bar.new) do
|
54
|
+
# posts = Post.all
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# Direct updates to a context value:
|
58
|
+
#
|
59
|
+
# ActiveSupport::ExecutionContext[:foo] = Bar.new
|
60
|
+
#
|
61
|
+
# Tag comments can be prepended to the query:
|
62
|
+
#
|
63
|
+
# ActiveRecord::QueryLogs.prepend_comment = true
|
64
|
+
#
|
65
|
+
# For applications where the content will not change during the lifetime of
|
66
|
+
# the request or job execution, the tags can be cached for reuse in every query:
|
67
|
+
#
|
68
|
+
# ActiveRecord::QueryLogs.cache_query_log_tags = true
|
69
|
+
#
|
70
|
+
# This option can be set during application configuration or in a Rails initializer:
|
71
|
+
#
|
72
|
+
# config.active_record.cache_query_log_tags = true
|
73
|
+
module QueryLogs
|
74
|
+
mattr_accessor :taggings, instance_accessor: false, default: {}
|
75
|
+
mattr_accessor :tags, instance_accessor: false, default: [ :application ]
|
76
|
+
mattr_accessor :prepend_comment, instance_accessor: false, default: false
|
77
|
+
mattr_accessor :cache_query_log_tags, instance_accessor: false, default: false
|
78
|
+
thread_mattr_accessor :cached_comment, instance_accessor: false
|
79
|
+
|
80
|
+
class << self
|
81
|
+
def call(sql) # :nodoc:
|
82
|
+
if prepend_comment
|
83
|
+
"#{self.comment} #{sql}"
|
84
|
+
else
|
85
|
+
"#{sql} #{self.comment}"
|
86
|
+
end.strip
|
87
|
+
end
|
88
|
+
|
89
|
+
def clear_cache # :nodoc:
|
90
|
+
self.cached_comment = nil
|
91
|
+
end
|
92
|
+
|
93
|
+
ActiveSupport::ExecutionContext.after_change { ActiveRecord::QueryLogs.clear_cache }
|
94
|
+
|
95
|
+
private
|
96
|
+
# Returns an SQL comment +String+ containing the query log tags.
|
97
|
+
# Sets and returns a cached comment if <tt>cache_query_log_tags</tt> is +true+.
|
98
|
+
def comment
|
99
|
+
if cache_query_log_tags
|
100
|
+
self.cached_comment ||= uncached_comment
|
101
|
+
else
|
102
|
+
uncached_comment
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def uncached_comment
|
107
|
+
content = tag_content
|
108
|
+
if content.present?
|
109
|
+
"/*#{escape_sql_comment(content)}*/"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def escape_sql_comment(content)
|
114
|
+
# Sanitize a string to appear within a SQL comment
|
115
|
+
# For compatibility, this also surrounding "/*+", "/*", and "*/"
|
116
|
+
# charcacters, possibly with single surrounding space.
|
117
|
+
# Then follows that by replacing any internal "*/" or "/ *" with
|
118
|
+
# "* /" or "/ *"
|
119
|
+
comment = content.to_s.dup
|
120
|
+
comment.gsub!(%r{\A\s*/\*\+?\s?|\s?\*/\s*\Z}, "")
|
121
|
+
comment.gsub!("*/", "* /")
|
122
|
+
comment.gsub!("/*", "/ *")
|
123
|
+
comment
|
124
|
+
end
|
125
|
+
|
126
|
+
def tag_content
|
127
|
+
context = ActiveSupport::ExecutionContext.to_h
|
128
|
+
|
129
|
+
tags.flat_map { |i| [*i] }.filter_map do |tag|
|
130
|
+
key, handler = tag
|
131
|
+
handler ||= taggings[key]
|
132
|
+
|
133
|
+
val = if handler.nil?
|
134
|
+
context[key]
|
135
|
+
elsif handler.respond_to?(:call)
|
136
|
+
if handler.arity == 0
|
137
|
+
handler.call
|
138
|
+
else
|
139
|
+
handler.call(context)
|
140
|
+
end
|
141
|
+
else
|
142
|
+
handler
|
143
|
+
end
|
144
|
+
"#{key}:#{val}" unless val.nil?
|
145
|
+
end.join(",")
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Querying
|
5
5
|
QUERYING_METHODS = [
|
6
|
-
:find, :find_by, :find_by!, :take, :take!, :first, :first!, :last, :last!,
|
6
|
+
:find, :find_by, :find_by!, :take, :take!, :sole, :find_sole_by, :first, :first!, :last, :last!,
|
7
7
|
:second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!,
|
8
8
|
:forty_two, :forty_two!, :third_to_last, :third_to_last!, :second_to_last, :second_to_last!,
|
9
9
|
:exists?, :any?, :many?, :none?, :one?,
|
@@ -12,12 +12,12 @@ module ActiveRecord
|
|
12
12
|
:create_or_find_by, :create_or_find_by!,
|
13
13
|
:destroy_all, :delete_all, :update_all, :touch_all, :destroy_by, :delete_by,
|
14
14
|
:find_each, :find_in_batches, :in_batches,
|
15
|
-
:select, :reselect, :order, :reorder, :group, :limit, :offset, :joins, :left_joins, :left_outer_joins,
|
16
|
-
:where, :rewhere, :preload, :extract_associated, :eager_load, :includes, :from, :lock, :readonly,
|
15
|
+
:select, :reselect, :order, :in_order_of, :reorder, :group, :limit, :offset, :joins, :left_joins, :left_outer_joins,
|
16
|
+
:where, :rewhere, :invert_where, :preload, :extract_associated, :eager_load, :includes, :from, :lock, :readonly,
|
17
17
|
:and, :or, :annotate, :optimizer_hints, :extending,
|
18
18
|
:having, :create_with, :distinct, :references, :none, :unscope, :merge, :except, :only,
|
19
19
|
:count, :average, :minimum, :maximum, :sum, :calculate,
|
20
|
-
:pluck, :pick, :ids, :strict_loading
|
20
|
+
:pluck, :pick, :ids, :strict_loading, :excluding, :without
|
21
21
|
].freeze # :nodoc:
|
22
22
|
delegate(*QUERYING_METHODS, to: :all)
|
23
23
|
|
@@ -39,12 +39,22 @@ module ActiveRecord
|
|
39
39
|
# Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
|
40
40
|
# # => [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "author"=>"Quentin"}>, ...]
|
41
41
|
#
|
42
|
-
# You can use the same string replacement techniques as you can with
|
42
|
+
# You can use the same string replacement techniques as you can with ActiveRecord::QueryMethods#where :
|
43
43
|
#
|
44
44
|
# Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
|
45
45
|
# Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
|
46
|
+
#
|
47
|
+
# Note that building your own SQL query string from user input may expose your application to
|
48
|
+
# injection attacks (https://guides.rubyonrails.org/security.html#sql-injection).
|
46
49
|
def find_by_sql(sql, binds = [], preparable: nil, &block)
|
47
|
-
|
50
|
+
_load_from_sql(_query_by_sql(sql, binds, preparable: preparable), &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def _query_by_sql(sql, binds = [], preparable: nil, async: false) # :nodoc:
|
54
|
+
connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable, async: async)
|
55
|
+
end
|
56
|
+
|
57
|
+
def _load_from_sql(result_set, &block) # :nodoc:
|
48
58
|
column_types = result_set.column_types
|
49
59
|
|
50
60
|
unless column_types.empty?
|
@@ -15,6 +15,7 @@ module ActiveRecord
|
|
15
15
|
# = Active Record Railtie
|
16
16
|
class Railtie < Rails::Railtie # :nodoc:
|
17
17
|
config.active_record = ActiveSupport::OrderedOptions.new
|
18
|
+
config.active_record.encryption = ActiveSupport::OrderedOptions.new
|
18
19
|
|
19
20
|
config.app_generators.orm :active_record, migration: true,
|
20
21
|
timestamps: true
|
@@ -30,6 +31,10 @@ module ActiveRecord
|
|
30
31
|
config.active_record.check_schema_cache_dump_version = true
|
31
32
|
config.active_record.maintain_test_schema = true
|
32
33
|
config.active_record.has_many_inversing = false
|
34
|
+
config.active_record.sqlite3_production_warning = true
|
35
|
+
config.active_record.query_log_tags_enabled = false
|
36
|
+
config.active_record.query_log_tags = [ :application ]
|
37
|
+
config.active_record.cache_query_log_tags = false
|
33
38
|
|
34
39
|
config.active_record.queues = ActiveSupport::InheritableOptions.new
|
35
40
|
|
@@ -60,7 +65,7 @@ module ActiveRecord
|
|
60
65
|
console.level = Rails.logger.level
|
61
66
|
Rails.logger.extend ActiveSupport::Logger.broadcast console
|
62
67
|
end
|
63
|
-
ActiveRecord
|
68
|
+
ActiveRecord.verbose_query_logs = false
|
64
69
|
end
|
65
70
|
|
66
71
|
runner do
|
@@ -70,7 +75,12 @@ module ActiveRecord
|
|
70
75
|
initializer "active_record.initialize_timezone" do
|
71
76
|
ActiveSupport.on_load(:active_record) do
|
72
77
|
self.time_zone_aware_attributes = true
|
73
|
-
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
initializer "active_record.postgresql_time_zone_aware_types" do
|
82
|
+
ActiveSupport.on_load(:active_record_postgresqladapter) do
|
83
|
+
ActiveRecord::Base.time_zone_aware_types << :timestamptz
|
74
84
|
end
|
75
85
|
end
|
76
86
|
|
@@ -83,21 +93,13 @@ module ActiveRecord
|
|
83
93
|
end
|
84
94
|
|
85
95
|
initializer "active_record.migration_error" do |app|
|
86
|
-
if config.active_record.
|
96
|
+
if config.active_record.migration_error == :page_load
|
87
97
|
config.app_middleware.insert_after ::ActionDispatch::Callbacks,
|
88
98
|
ActiveRecord::Migration::CheckPending,
|
89
99
|
file_watcher: app.config.file_watcher
|
90
100
|
end
|
91
101
|
end
|
92
102
|
|
93
|
-
initializer "active_record.database_selector" do
|
94
|
-
if options = config.active_record.delete(:database_selector)
|
95
|
-
resolver = config.active_record.delete(:database_resolver)
|
96
|
-
operations = config.active_record.delete(:database_resolver_context)
|
97
|
-
config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
103
|
initializer "Check for cache versioning support" do
|
102
104
|
config.after_initialize do |app|
|
103
105
|
ActiveSupport.on_load(:active_record) do
|
@@ -124,9 +126,9 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
124
126
|
end
|
125
127
|
|
126
128
|
initializer "active_record.check_schema_cache_dump" do
|
127
|
-
check_schema_cache_dump_version = config.active_record.
|
129
|
+
check_schema_cache_dump_version = config.active_record.check_schema_cache_dump_version
|
128
130
|
|
129
|
-
if config.active_record.
|
131
|
+
if config.active_record.use_schema_cache_dump && !config.active_record.lazily_load_schema_cache
|
130
132
|
config.after_initialize do |app|
|
131
133
|
ActiveSupport.on_load(:active_record) do
|
132
134
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first
|
@@ -149,11 +151,12 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
149
151
|
next if current_version.nil?
|
150
152
|
|
151
153
|
if cache.version != current_version
|
152
|
-
warn "Ignoring #{filename} because it has expired. The current schema version is #{current_version}, but the one in the cache is #{cache.version}."
|
154
|
+
warn "Ignoring #{filename} because it has expired. The current schema version is #{current_version}, but the one in the schema cache file is #{cache.version}."
|
153
155
|
next
|
154
156
|
end
|
155
157
|
end
|
156
158
|
|
159
|
+
Rails.logger.info("Using schema cache file #{filename}")
|
157
160
|
connection_pool.set_schema_cache(cache)
|
158
161
|
end
|
159
162
|
end
|
@@ -166,10 +169,6 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
166
169
|
if app.config.eager_load
|
167
170
|
begin
|
168
171
|
descendants.each do |model|
|
169
|
-
# SchemaMigration and InternalMetadata both override `table_exists?`
|
170
|
-
# to bypass the schema cache, so skip them to avoid the extra queries.
|
171
|
-
next if model._internal?
|
172
|
-
|
173
172
|
# If the schema cache was loaded from a dump, we can use it without connecting
|
174
173
|
schema_cache = model.connection_pool.schema_cache
|
175
174
|
|
@@ -201,12 +200,58 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
201
200
|
end
|
202
201
|
end
|
203
202
|
|
203
|
+
SQLITE3_PRODUCTION_WARN = "You are running SQLite in production, this is generally not recommended."\
|
204
|
+
" You can disable this warning by setting \"config.active_record.sqlite3_production_warning=false\"."
|
205
|
+
initializer "active_record.sqlite3_production_warning" do
|
206
|
+
if config.active_record.sqlite3_production_warning && Rails.env.production?
|
207
|
+
ActiveSupport.on_load(:active_record_sqlite3adapter) do
|
208
|
+
Rails.logger.warn(SQLITE3_PRODUCTION_WARN)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
204
213
|
initializer "active_record.set_configs" do |app|
|
214
|
+
configs = app.config.active_record
|
215
|
+
|
216
|
+
config.after_initialize do
|
217
|
+
configs.each do |k, v|
|
218
|
+
next if k == :encryption
|
219
|
+
setter = "#{k}="
|
220
|
+
if ActiveRecord.respond_to?(setter)
|
221
|
+
ActiveRecord.send(setter, v)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
205
226
|
ActiveSupport.on_load(:active_record) do
|
206
|
-
|
227
|
+
# Configs used in other initializers
|
228
|
+
configs = configs.except(
|
229
|
+
:migration_error,
|
230
|
+
:database_selector,
|
231
|
+
:database_resolver,
|
232
|
+
:database_resolver_context,
|
233
|
+
:shard_selector,
|
234
|
+
:shard_resolver,
|
235
|
+
:query_log_tags_enabled,
|
236
|
+
:query_log_tags,
|
237
|
+
:cache_query_log_tags,
|
238
|
+
:sqlite3_production_warning,
|
239
|
+
:check_schema_cache_dump_version,
|
240
|
+
:use_schema_cache_dump
|
241
|
+
)
|
207
242
|
|
208
243
|
configs.each do |k, v|
|
209
|
-
|
244
|
+
next if k == :encryption
|
245
|
+
setter = "#{k}="
|
246
|
+
# Some existing initializers might rely on Active Record configuration
|
247
|
+
# being copied from the config object to their actual destination when
|
248
|
+
# `ActiveRecord::Base` is loaded.
|
249
|
+
# So to preserve backward compatibility we copy the config a second time.
|
250
|
+
if ActiveRecord.respond_to?(setter)
|
251
|
+
ActiveRecord.send(setter, v)
|
252
|
+
else
|
253
|
+
send(setter, v)
|
254
|
+
end
|
210
255
|
end
|
211
256
|
end
|
212
257
|
end
|
@@ -215,10 +260,11 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
215
260
|
# and then establishes the connection.
|
216
261
|
initializer "active_record.initialize_database" do
|
217
262
|
ActiveSupport.on_load(:active_record) do
|
218
|
-
if ActiveRecord
|
219
|
-
self.connection_handlers = { writing_role => ActiveRecord::Base.default_connection_handler }
|
263
|
+
if ActiveRecord.legacy_connection_handling
|
264
|
+
self.connection_handlers = { ActiveRecord.writing_role => ActiveRecord::Base.default_connection_handler }
|
220
265
|
end
|
221
266
|
self.configurations = Rails.application.config.database_configuration
|
267
|
+
|
222
268
|
establish_connection
|
223
269
|
end
|
224
270
|
end
|
@@ -244,6 +290,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
244
290
|
|
245
291
|
initializer "active_record.set_executor_hooks" do
|
246
292
|
ActiveRecord::QueryCache.install_executor_hooks
|
293
|
+
ActiveRecord::AsynchronousQueriesTracker.install_executor_hooks
|
247
294
|
end
|
248
295
|
|
249
296
|
initializer "active_record.add_watchable_files" do |app|
|
@@ -279,5 +326,72 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
279
326
|
self.signed_id_verifier_secret ||= -> { Rails.application.key_generator.generate_key("active_record/signed_id") }
|
280
327
|
end
|
281
328
|
end
|
329
|
+
|
330
|
+
initializer "active_record_encryption.configuration" do |app|
|
331
|
+
ActiveRecord::Encryption.configure \
|
332
|
+
primary_key: app.credentials.dig(:active_record_encryption, :primary_key),
|
333
|
+
deterministic_key: app.credentials.dig(:active_record_encryption, :deterministic_key),
|
334
|
+
key_derivation_salt: app.credentials.dig(:active_record_encryption, :key_derivation_salt),
|
335
|
+
**config.active_record.encryption
|
336
|
+
|
337
|
+
ActiveSupport.on_load(:active_record) do
|
338
|
+
# Support extended queries for deterministic attributes and validations
|
339
|
+
if ActiveRecord::Encryption.config.extend_queries
|
340
|
+
ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
|
341
|
+
ActiveRecord::Encryption::ExtendedDeterministicUniquenessValidator.install_support
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
ActiveSupport.on_load(:active_record_fixture_set) do
|
346
|
+
# Encrypt active record fixtures
|
347
|
+
if ActiveRecord::Encryption.config.encrypt_fixtures
|
348
|
+
ActiveRecord::Fixture.prepend ActiveRecord::Encryption::EncryptedFixtures
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
# Filtered params
|
353
|
+
ActiveSupport.on_load(:action_controller, run_once: true) do
|
354
|
+
if ActiveRecord::Encryption.config.add_to_filter_parameters
|
355
|
+
ActiveRecord::Encryption.install_auto_filtered_parameters_hook(app)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
initializer "active_record.query_log_tags_config" do |app|
|
361
|
+
config.after_initialize do
|
362
|
+
if app.config.active_record.query_log_tags_enabled
|
363
|
+
ActiveRecord.query_transformers << ActiveRecord::QueryLogs
|
364
|
+
ActiveRecord::QueryLogs.taggings.merge!(
|
365
|
+
application: Rails.application.class.name.split("::").first,
|
366
|
+
pid: -> { Process.pid },
|
367
|
+
socket: -> { ActiveRecord::Base.connection_db_config.socket },
|
368
|
+
db_host: -> { ActiveRecord::Base.connection_db_config.host },
|
369
|
+
database: -> { ActiveRecord::Base.connection_db_config.database }
|
370
|
+
)
|
371
|
+
|
372
|
+
if app.config.active_record.query_log_tags.present?
|
373
|
+
ActiveRecord::QueryLogs.tags = app.config.active_record.query_log_tags
|
374
|
+
end
|
375
|
+
|
376
|
+
if app.config.active_record.cache_query_log_tags
|
377
|
+
ActiveRecord::QueryLogs.cache_query_log_tags = true
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
initializer "active_record.unregister_current_scopes_on_unload" do |app|
|
384
|
+
config.after_initialize do
|
385
|
+
unless app.config.cache_classes
|
386
|
+
Rails.autoloaders.main.on_unload do |_cpath, value, _abspath|
|
387
|
+
# Conditions are written this way to be robust against custom
|
388
|
+
# implementations of value#is_a? or value#<.
|
389
|
+
if Class === value && ActiveRecord::Base > value
|
390
|
+
value.current_scope = nil
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
282
396
|
end
|
283
397
|
end
|