activerecord 6.1.3.2 → 7.0.0.alpha2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +734 -1058
- 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 +35 -7
- data/lib/active_record/associations/association_scope.rb +1 -3
- data/lib/active_record/associations/belongs_to_association.rb +16 -6
- 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 +1 -1
- 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 +24 -25
- 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/preloader/association.rb +161 -49
- data/lib/active_record/associations/preloader/batch.rb +51 -0
- data/lib/active_record/associations/preloader/branch.rb +147 -0
- data/lib/active_record/associations/preloader/through_association.rb +37 -11
- data/lib/active_record/associations/preloader.rb +46 -110
- data/lib/active_record/associations/singular_association.rb +8 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +76 -81
- data/lib/active_record/asynchronous_queries_tracker.rb +57 -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 +41 -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 +6 -9
- data/lib/active_record/attributes.rb +24 -35
- data/lib/active_record/autosave_association.rb +3 -18
- data/lib/active_record/base.rb +19 -1
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/coders/yaml_column.rb +11 -1
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -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 +31 -558
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
- data/lib/active_record/connection_adapters/abstract/quoting.rb +14 -7
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -18
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -9
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
- data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
- data/lib/active_record/connection_adapters/abstract_adapter.rb +115 -69
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +6 -2
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -21
- data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
- data/lib/active_record/connection_adapters/pool_config.rb +1 -3
- data/lib/active_record/connection_adapters/pool_manager.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -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 +6 -6
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
- data/lib/active_record/connection_adapters/schema_cache.rb +35 -4
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +0 -2
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -17
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
- data/lib/active_record/connection_adapters.rb +8 -5
- data/lib/active_record/connection_handling.rb +20 -38
- data/lib/active_record/core.rb +129 -117
- data/lib/active_record/database_configurations/database_config.rb +12 -0
- data/lib/active_record/database_configurations/hash_config.rb +27 -1
- data/lib/active_record/database_configurations/url_config.rb +2 -2
- data/lib/active_record/database_configurations.rb +18 -9
- data/lib/active_record/delegated_type.rb +33 -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 +29 -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 +80 -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 +44 -46
- data/lib/active_record/errors.rb +66 -3
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/table_row.rb +40 -5
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +16 -11
- 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 +39 -6
- data/lib/active_record/integration.rb +1 -1
- data/lib/active_record/internal_metadata.rb +3 -5
- data/lib/active_record/legacy_yaml_adapter.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +10 -9
- data/lib/active_record/log_subscriber.rb +6 -2
- 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/migration/command_recorder.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +83 -1
- 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 +46 -32
- data/lib/active_record/nested_attributes.rb +3 -3
- data/lib/active_record/no_touching.rb +2 -2
- data/lib/active_record/null_relation.rb +2 -6
- data/lib/active_record/persistence.rb +134 -45
- data/lib/active_record/query_cache.rb +2 -2
- data/lib/active_record/query_logs.rb +203 -0
- data/lib/active_record/querying.rb +15 -5
- data/lib/active_record/railtie.rb +117 -17
- data/lib/active_record/railties/controller_runtime.rb +1 -1
- data/lib/active_record/railties/databases.rake +83 -58
- data/lib/active_record/readonly_attributes.rb +11 -0
- data/lib/active_record/reflection.rb +45 -44
- 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 +42 -25
- data/lib/active_record/relation/delegation.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +32 -23
- 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 +233 -50
- data/lib/active_record/relation/record_fetch_warning.rb +2 -2
- data/lib/active_record/relation/spawn_methods.rb +2 -2
- data/lib/active_record/relation/where_clause.rb +22 -15
- data/lib/active_record/relation.rb +170 -87
- data/lib/active_record/result.rb +17 -2
- data/lib/active_record/runtime_registry.rb +2 -4
- data/lib/active_record/sanitization.rb +11 -7
- data/lib/active_record/schema_dumper.rb +3 -3
- data/lib/active_record/schema_migration.rb +0 -4
- data/lib/active_record/scoping/default.rb +62 -15
- data/lib/active_record/scoping/named.rb +3 -11
- data/lib/active_record/scoping.rb +40 -22
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/signed_id.rb +1 -1
- data/lib/active_record/statement_cache.rb +2 -2
- data/lib/active_record/tasks/database_tasks.rb +107 -23
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +45 -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/numericality.rb +1 -1
- data/lib/active_record.rb +170 -2
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -2
- data/lib/arel/collectors/composite.rb +3 -3
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +18 -22
- data/lib/arel/delete_manager.rb +2 -4
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/delete_statement.rb +8 -13
- data/lib/arel/nodes/homogeneous_in.rb +4 -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 +3 -2
- data/lib/arel/predications.rb +3 -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 +2 -4
- data/lib/arel/visitors/dot.rb +80 -90
- data/lib/arel/visitors/mysql.rb +6 -1
- data/lib/arel/visitors/postgresql.rb +0 -10
- data/lib/arel/visitors/to_sql.rb +44 -3
- data/lib/arel.rb +1 -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
- metadata +55 -16
@@ -28,7 +28,7 @@ module ActiveRecord
|
|
28
28
|
def self.run
|
29
29
|
pools = []
|
30
30
|
|
31
|
-
if ActiveRecord
|
31
|
+
if ActiveRecord.legacy_connection_handling
|
32
32
|
ActiveRecord::Base.connection_handlers.each do |key, handler|
|
33
33
|
pools.concat(handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! })
|
34
34
|
end
|
@@ -42,7 +42,7 @@ module ActiveRecord
|
|
42
42
|
def self.complete(pools)
|
43
43
|
pools.each { |pool| pool.disable_query_cache! }
|
44
44
|
|
45
|
-
if ActiveRecord
|
45
|
+
if ActiveRecord.legacy_connection_handling
|
46
46
|
ActiveRecord::Base.connection_handlers.each do |_, handler|
|
47
47
|
handler.connection_pool_list.each do |pool|
|
48
48
|
pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
|
@@ -0,0 +1,203 @@
|
|
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
|
+
# Example:
|
37
|
+
#
|
38
|
+
# tags = [
|
39
|
+
# :application,
|
40
|
+
# {
|
41
|
+
# custom_tag: ->(context) { context[:controller].controller_name },
|
42
|
+
# custom_value: -> { Custom.value },
|
43
|
+
# }
|
44
|
+
# ]
|
45
|
+
# ActiveRecord::QueryLogs.tags = tags
|
46
|
+
#
|
47
|
+
# The QueryLogs +context+ can be manipulated via +update_context+ & +set_context+ methods.
|
48
|
+
#
|
49
|
+
# Direct updates to a context value:
|
50
|
+
#
|
51
|
+
# ActiveRecord::QueryLogs.update_context(foo: Bar.new)
|
52
|
+
#
|
53
|
+
# Temporary updates limited to the execution of a block:
|
54
|
+
#
|
55
|
+
# ActiveRecord::QueryLogs.set_context(foo: Bar.new) do
|
56
|
+
# posts = Post.all
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# Tag comments can be prepended to the query:
|
60
|
+
#
|
61
|
+
# ActiveRecord::QueryLogs.prepend_comment = true
|
62
|
+
#
|
63
|
+
# For applications where the content will not change during the lifetime of
|
64
|
+
# the request or job execution, the tags can be cached for reuse in every query:
|
65
|
+
#
|
66
|
+
# ActiveRecord::QueryLogs.cache_query_log_tags = true
|
67
|
+
#
|
68
|
+
# This option can be set during application configuration or in a Rails initializer:
|
69
|
+
#
|
70
|
+
# config.active_record.cache_query_log_tags = true
|
71
|
+
module QueryLogs
|
72
|
+
mattr_accessor :taggings, instance_accessor: false, default: {}
|
73
|
+
mattr_accessor :tags, instance_accessor: false, default: [ :application ]
|
74
|
+
mattr_accessor :prepend_comment, instance_accessor: false, default: false
|
75
|
+
mattr_accessor :cache_query_log_tags, instance_accessor: false, default: false
|
76
|
+
thread_mattr_accessor :cached_comment, instance_accessor: false
|
77
|
+
|
78
|
+
class NullObject # :nodoc:
|
79
|
+
def method_missing(method, *args, &block)
|
80
|
+
NullObject.new
|
81
|
+
end
|
82
|
+
|
83
|
+
def nil?
|
84
|
+
true
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
def respond_to_missing?(method, include_private = false)
|
89
|
+
true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class << self
|
94
|
+
# Updates the context used to construct tags in the SQL comment.
|
95
|
+
# Resets the cached comment if <tt>cache_query_log_tags</tt> is +true+.
|
96
|
+
def update_context(**options)
|
97
|
+
context.merge!(**options.symbolize_keys)
|
98
|
+
self.cached_comment = nil
|
99
|
+
end
|
100
|
+
|
101
|
+
# Updates the context used to construct tags in the SQL comment during
|
102
|
+
# execution of the provided block. Resets the provided keys to their
|
103
|
+
# previous value once the block exits.
|
104
|
+
def set_context(**options)
|
105
|
+
keys = options.keys
|
106
|
+
previous_context = keys.zip(context.values_at(*keys)).to_h
|
107
|
+
update_context(**options)
|
108
|
+
yield if block_given?
|
109
|
+
ensure
|
110
|
+
update_context(**previous_context)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Temporarily tag any query executed within `&block`. Can be nested.
|
114
|
+
def with_tag(tag, &block)
|
115
|
+
inline_tags.push(tag)
|
116
|
+
yield if block_given?
|
117
|
+
ensure
|
118
|
+
inline_tags.pop
|
119
|
+
end
|
120
|
+
|
121
|
+
def call(sql) # :nodoc:
|
122
|
+
parts = self.comments
|
123
|
+
if prepend_comment
|
124
|
+
parts << sql
|
125
|
+
else
|
126
|
+
parts.unshift(sql)
|
127
|
+
end
|
128
|
+
parts.join(" ")
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
# Returns an array of comments which need to be added to the query, comprised
|
133
|
+
# of configured and inline tags.
|
134
|
+
def comments
|
135
|
+
[ comment, inline_comment ].compact
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns an SQL comment +String+ containing the query log tags.
|
139
|
+
# Sets and returns a cached comment if <tt>cache_query_log_tags</tt> is +true+.
|
140
|
+
def comment
|
141
|
+
if cache_query_log_tags
|
142
|
+
self.cached_comment ||= uncached_comment
|
143
|
+
else
|
144
|
+
uncached_comment
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def uncached_comment
|
149
|
+
content = tag_content
|
150
|
+
if content.present?
|
151
|
+
"/*#{escape_sql_comment(content)}*/"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Returns a +String+ containing any inline comments from +with_tag+.
|
156
|
+
def inline_comment
|
157
|
+
return nil unless inline_tags.present?
|
158
|
+
"/*#{escape_sql_comment(inline_tag_content)}*/"
|
159
|
+
end
|
160
|
+
|
161
|
+
# Return the set of active inline tags from +with_tag+.
|
162
|
+
def inline_tags
|
163
|
+
if context[:inline_tags].nil?
|
164
|
+
context[:inline_tags] = []
|
165
|
+
else
|
166
|
+
context[:inline_tags]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def context
|
171
|
+
Thread.current[:active_record_query_log_tags_context] ||= Hash.new { NullObject.new }
|
172
|
+
end
|
173
|
+
|
174
|
+
def escape_sql_comment(content)
|
175
|
+
content.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "")
|
176
|
+
end
|
177
|
+
|
178
|
+
def tag_content
|
179
|
+
tags.flat_map { |i| [*i] }.filter_map do |tag|
|
180
|
+
key, handler = tag
|
181
|
+
handler ||= taggings[key]
|
182
|
+
|
183
|
+
val = if handler.nil?
|
184
|
+
context[key]
|
185
|
+
elsif handler.respond_to?(:call)
|
186
|
+
if handler.arity == 0
|
187
|
+
handler.call
|
188
|
+
else
|
189
|
+
handler.call(context)
|
190
|
+
end
|
191
|
+
else
|
192
|
+
handler
|
193
|
+
end
|
194
|
+
"#{key}:#{val}" unless val.nil?
|
195
|
+
end.join(",")
|
196
|
+
end
|
197
|
+
|
198
|
+
def inline_tag_content
|
199
|
+
inline_tags.join
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
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
|
|
@@ -43,8 +43,18 @@ module ActiveRecord
|
|
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,6 @@ 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
|
-
self.default_timezone = :utc
|
74
78
|
end
|
75
79
|
end
|
76
80
|
|
@@ -83,7 +87,7 @@ module ActiveRecord
|
|
83
87
|
end
|
84
88
|
|
85
89
|
initializer "active_record.migration_error" do |app|
|
86
|
-
if config.active_record.
|
90
|
+
if config.active_record.migration_error == :page_load
|
87
91
|
config.app_middleware.insert_after ::ActionDispatch::Callbacks,
|
88
92
|
ActiveRecord::Migration::CheckPending,
|
89
93
|
file_watcher: app.config.file_watcher
|
@@ -91,9 +95,9 @@ module ActiveRecord
|
|
91
95
|
end
|
92
96
|
|
93
97
|
initializer "active_record.database_selector" do
|
94
|
-
if options = config.active_record.
|
95
|
-
resolver = config.active_record.
|
96
|
-
operations = config.active_record.
|
98
|
+
if options = config.active_record.database_selector
|
99
|
+
resolver = config.active_record.database_resolver
|
100
|
+
operations = config.active_record.database_resolver_context
|
97
101
|
config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options
|
98
102
|
end
|
99
103
|
end
|
@@ -124,9 +128,9 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
124
128
|
end
|
125
129
|
|
126
130
|
initializer "active_record.check_schema_cache_dump" do
|
127
|
-
check_schema_cache_dump_version = config.active_record.
|
131
|
+
check_schema_cache_dump_version = config.active_record.check_schema_cache_dump_version
|
128
132
|
|
129
|
-
if config.active_record.
|
133
|
+
if config.active_record.use_schema_cache_dump
|
130
134
|
config.after_initialize do |app|
|
131
135
|
ActiveSupport.on_load(:active_record) do
|
132
136
|
db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first
|
@@ -149,11 +153,12 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
149
153
|
next if current_version.nil?
|
150
154
|
|
151
155
|
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}."
|
156
|
+
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
157
|
next
|
154
158
|
end
|
155
159
|
end
|
156
160
|
|
161
|
+
Rails.logger.info("Using schema cache file #{filename}")
|
157
162
|
connection_pool.set_schema_cache(cache)
|
158
163
|
end
|
159
164
|
end
|
@@ -166,10 +171,6 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
166
171
|
if app.config.eager_load
|
167
172
|
begin
|
168
173
|
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
174
|
# If the schema cache was loaded from a dump, we can use it without connecting
|
174
175
|
schema_cache = model.connection_pool.schema_cache
|
175
176
|
|
@@ -201,12 +202,56 @@ To keep using the current cache store, you can turn off cache versioning entirel
|
|
201
202
|
end
|
202
203
|
end
|
203
204
|
|
205
|
+
SQLITE3_PRODUCTION_WARN = "You are running SQLite in production, this is generally not recommended."\
|
206
|
+
" You can disable this warning by setting \"config.active_record.sqlite3_production_warning=false\"."
|
207
|
+
initializer "active_record.sqlite3_production_warning" do
|
208
|
+
if config.active_record.sqlite3_production_warning && Rails.env.production?
|
209
|
+
ActiveSupport.on_load(:active_record_sqlite3adapter) do
|
210
|
+
Rails.logger.warn(SQLITE3_PRODUCTION_WARN)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
204
215
|
initializer "active_record.set_configs" do |app|
|
216
|
+
configs = app.config.active_record
|
217
|
+
|
218
|
+
config.after_initialize do
|
219
|
+
configs.each do |k, v|
|
220
|
+
next if k == :encryption
|
221
|
+
setter = "#{k}="
|
222
|
+
if ActiveRecord.respond_to?(setter)
|
223
|
+
ActiveRecord.send(setter, v)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
205
228
|
ActiveSupport.on_load(:active_record) do
|
206
|
-
|
229
|
+
# Configs used in other initializers
|
230
|
+
configs = configs.except(
|
231
|
+
:migration_error,
|
232
|
+
:database_selector,
|
233
|
+
:database_resolver,
|
234
|
+
:database_resolver_context,
|
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,58 @@ 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) do
|
354
|
+
if ActiveRecord::Encryption.config.add_to_filter_parameters
|
355
|
+
ActiveRecord::Encryption.install_auto_filtered_parameters(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
|
282
382
|
end
|
283
383
|
end
|