activerecord 6.1.7.8 → 7.0.8.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1582 -1018
  3. data/README.rdoc +3 -3
  4. data/lib/active_record/aggregations.rb +1 -1
  5. data/lib/active_record/association_relation.rb +0 -10
  6. data/lib/active_record/associations/association.rb +33 -17
  7. data/lib/active_record/associations/association_scope.rb +1 -3
  8. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  10. data/lib/active_record/associations/builder/association.rb +8 -2
  11. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  12. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  13. data/lib/active_record/associations/builder/has_many.rb +3 -2
  14. data/lib/active_record/associations/builder/has_one.rb +2 -1
  15. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  16. data/lib/active_record/associations/collection_association.rb +20 -22
  17. data/lib/active_record/associations/collection_proxy.rb +15 -5
  18. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  19. data/lib/active_record/associations/has_many_association.rb +8 -5
  20. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  21. data/lib/active_record/associations/has_one_association.rb +10 -7
  22. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency.rb +23 -15
  24. data/lib/active_record/associations/preloader/association.rb +186 -52
  25. data/lib/active_record/associations/preloader/batch.rb +48 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  28. data/lib/active_record/associations/preloader.rb +39 -113
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +3 -3
  31. data/lib/active_record/associations.rb +138 -100
  32. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +49 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +8 -6
  39. data/lib/active_record/attribute_methods/serialization.rb +57 -19
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +19 -22
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +8 -23
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +14 -16
  47. data/lib/active_record/coders/yaml_column.rb +4 -8
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +52 -23
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +82 -25
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +144 -82
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +115 -85
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +37 -25
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -23
  66. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  68. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  70. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  71. data/lib/active_record/connection_adapters/postgresql/column.rb +19 -1
  72. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -17
  73. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  77. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  78. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  81. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  82. data/lib/active_record/connection_adapters/postgresql/quoting.rb +76 -73
  83. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
  84. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  85. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  86. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  87. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +40 -21
  88. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  89. data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -106
  90. data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
  91. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
  92. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +33 -18
  93. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -0
  94. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +19 -17
  95. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +98 -36
  96. data/lib/active_record/connection_adapters.rb +6 -5
  97. data/lib/active_record/connection_handling.rb +49 -55
  98. data/lib/active_record/core.rb +123 -148
  99. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  100. data/lib/active_record/database_configurations/database_config.rb +12 -9
  101. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  102. data/lib/active_record/database_configurations/url_config.rb +2 -2
  103. data/lib/active_record/database_configurations.rb +15 -32
  104. data/lib/active_record/delegated_type.rb +53 -12
  105. data/lib/active_record/destroy_association_async_job.rb +1 -1
  106. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  107. data/lib/active_record/dynamic_matchers.rb +1 -1
  108. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  109. data/lib/active_record/encryption/cipher.rb +53 -0
  110. data/lib/active_record/encryption/config.rb +44 -0
  111. data/lib/active_record/encryption/configurable.rb +67 -0
  112. data/lib/active_record/encryption/context.rb +35 -0
  113. data/lib/active_record/encryption/contexts.rb +72 -0
  114. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  115. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  116. data/lib/active_record/encryption/encryptable_record.rb +206 -0
  117. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  118. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  119. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  120. data/lib/active_record/encryption/encryptor.rb +155 -0
  121. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  122. data/lib/active_record/encryption/errors.rb +15 -0
  123. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  124. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  125. data/lib/active_record/encryption/key.rb +28 -0
  126. data/lib/active_record/encryption/key_generator.rb +42 -0
  127. data/lib/active_record/encryption/key_provider.rb +46 -0
  128. data/lib/active_record/encryption/message.rb +33 -0
  129. data/lib/active_record/encryption/message_serializer.rb +90 -0
  130. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  131. data/lib/active_record/encryption/properties.rb +76 -0
  132. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  133. data/lib/active_record/encryption/scheme.rb +99 -0
  134. data/lib/active_record/encryption.rb +55 -0
  135. data/lib/active_record/enum.rb +50 -43
  136. data/lib/active_record/errors.rb +67 -4
  137. data/lib/active_record/explain_registry.rb +11 -6
  138. data/lib/active_record/explain_subscriber.rb +1 -1
  139. data/lib/active_record/fixture_set/file.rb +15 -1
  140. data/lib/active_record/fixture_set/table_row.rb +41 -6
  141. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  142. data/lib/active_record/fixtures.rb +20 -23
  143. data/lib/active_record/future_result.rb +139 -0
  144. data/lib/active_record/gem_version.rb +5 -5
  145. data/lib/active_record/inheritance.rb +55 -17
  146. data/lib/active_record/insert_all.rb +80 -14
  147. data/lib/active_record/integration.rb +4 -3
  148. data/lib/active_record/internal_metadata.rb +1 -5
  149. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  150. data/lib/active_record/locking/optimistic.rb +36 -21
  151. data/lib/active_record/locking/pessimistic.rb +10 -4
  152. data/lib/active_record/log_subscriber.rb +23 -7
  153. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  154. data/lib/active_record/middleware/database_selector.rb +18 -6
  155. data/lib/active_record/middleware/shard_selector.rb +60 -0
  156. data/lib/active_record/migration/command_recorder.rb +8 -9
  157. data/lib/active_record/migration/compatibility.rb +93 -46
  158. data/lib/active_record/migration/join_table.rb +1 -1
  159. data/lib/active_record/migration.rb +167 -87
  160. data/lib/active_record/model_schema.rb +58 -59
  161. data/lib/active_record/nested_attributes.rb +13 -12
  162. data/lib/active_record/no_touching.rb +3 -3
  163. data/lib/active_record/null_relation.rb +2 -6
  164. data/lib/active_record/persistence.rb +231 -61
  165. data/lib/active_record/query_cache.rb +2 -2
  166. data/lib/active_record/query_logs.rb +149 -0
  167. data/lib/active_record/querying.rb +16 -6
  168. data/lib/active_record/railtie.rb +136 -22
  169. data/lib/active_record/railties/controller_runtime.rb +4 -5
  170. data/lib/active_record/railties/databases.rake +78 -136
  171. data/lib/active_record/readonly_attributes.rb +11 -0
  172. data/lib/active_record/reflection.rb +80 -49
  173. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  174. data/lib/active_record/relation/batches.rb +6 -6
  175. data/lib/active_record/relation/calculations.rb +92 -60
  176. data/lib/active_record/relation/delegation.rb +7 -7
  177. data/lib/active_record/relation/finder_methods.rb +31 -35
  178. data/lib/active_record/relation/merger.rb +20 -13
  179. data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
  180. data/lib/active_record/relation/predicate_builder.rb +1 -6
  181. data/lib/active_record/relation/query_attribute.rb +28 -11
  182. data/lib/active_record/relation/query_methods.rb +304 -68
  183. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  184. data/lib/active_record/relation/spawn_methods.rb +2 -2
  185. data/lib/active_record/relation/where_clause.rb +10 -19
  186. data/lib/active_record/relation.rb +189 -88
  187. data/lib/active_record/result.rb +23 -11
  188. data/lib/active_record/runtime_registry.rb +9 -13
  189. data/lib/active_record/sanitization.rb +17 -12
  190. data/lib/active_record/schema.rb +38 -23
  191. data/lib/active_record/schema_dumper.rb +29 -19
  192. data/lib/active_record/schema_migration.rb +4 -4
  193. data/lib/active_record/scoping/default.rb +60 -13
  194. data/lib/active_record/scoping/named.rb +3 -11
  195. data/lib/active_record/scoping.rb +64 -34
  196. data/lib/active_record/serialization.rb +6 -1
  197. data/lib/active_record/signed_id.rb +3 -3
  198. data/lib/active_record/store.rb +2 -2
  199. data/lib/active_record/suppressor.rb +11 -15
  200. data/lib/active_record/table_metadata.rb +6 -2
  201. data/lib/active_record/tasks/database_tasks.rb +127 -60
  202. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  203. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
  204. data/lib/active_record/test_databases.rb +1 -1
  205. data/lib/active_record/test_fixtures.rb +9 -6
  206. data/lib/active_record/timestamp.rb +3 -4
  207. data/lib/active_record/transactions.rb +12 -17
  208. data/lib/active_record/translation.rb +3 -3
  209. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  210. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  211. data/lib/active_record/type/internal/timezone.rb +2 -2
  212. data/lib/active_record/type/serialized.rb +9 -5
  213. data/lib/active_record/type/type_map.rb +17 -20
  214. data/lib/active_record/type.rb +1 -2
  215. data/lib/active_record/validations/associated.rb +4 -4
  216. data/lib/active_record/validations/presence.rb +2 -2
  217. data/lib/active_record/validations/uniqueness.rb +4 -4
  218. data/lib/active_record/version.rb +1 -1
  219. data/lib/active_record.rb +225 -27
  220. data/lib/arel/attributes/attribute.rb +0 -8
  221. data/lib/arel/crud.rb +28 -22
  222. data/lib/arel/delete_manager.rb +18 -4
  223. data/lib/arel/filter_predications.rb +9 -0
  224. data/lib/arel/insert_manager.rb +2 -3
  225. data/lib/arel/nodes/and.rb +4 -0
  226. data/lib/arel/nodes/casted.rb +1 -1
  227. data/lib/arel/nodes/delete_statement.rb +12 -13
  228. data/lib/arel/nodes/filter.rb +10 -0
  229. data/lib/arel/nodes/function.rb +1 -0
  230. data/lib/arel/nodes/insert_statement.rb +2 -2
  231. data/lib/arel/nodes/select_core.rb +2 -2
  232. data/lib/arel/nodes/select_statement.rb +2 -2
  233. data/lib/arel/nodes/update_statement.rb +8 -3
  234. data/lib/arel/nodes.rb +1 -0
  235. data/lib/arel/predications.rb +11 -3
  236. data/lib/arel/select_manager.rb +10 -4
  237. data/lib/arel/table.rb +0 -1
  238. data/lib/arel/tree_manager.rb +0 -12
  239. data/lib/arel/update_manager.rb +18 -4
  240. data/lib/arel/visitors/dot.rb +80 -90
  241. data/lib/arel/visitors/mysql.rb +8 -2
  242. data/lib/arel/visitors/postgresql.rb +0 -10
  243. data/lib/arel/visitors/to_sql.rb +58 -2
  244. data/lib/arel.rb +2 -1
  245. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  246. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  247. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  248. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  249. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  250. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  251. metadata +53 -9
@@ -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 <tt>ActiveRecord::QueryMethods#where</tt>:
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
- result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
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::Base.verbose_query_logs = false
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
- self.default_timezone = :utc
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.delete(:migration_error) == :page_load
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.delete(:check_schema_cache_dump_version)
129
+ check_schema_cache_dump_version = config.active_record.check_schema_cache_dump_version
128
130
 
129
- if config.active_record.delete(:use_schema_cache_dump)
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
- configs = app.config.active_record
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
- send "#{k}=", v
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::Base.legacy_connection_handling
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
@@ -5,7 +5,7 @@ require "active_record/log_subscriber"
5
5
 
6
6
  module ActiveRecord
7
7
  module Railties # :nodoc:
8
- module ControllerRuntime #:nodoc:
8
+ module ControllerRuntime # :nodoc:
9
9
  extend ActiveSupport::Concern
10
10
 
11
11
  module ClassMethods # :nodoc:
@@ -28,7 +28,7 @@ module ActiveRecord
28
28
  end
29
29
 
30
30
  def cleanup_view_runtime
31
- if logger && logger.info? && ActiveRecord::Base.connected?
31
+ if logger && logger.info?
32
32
  db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
33
33
  self.db_runtime = (db_runtime || 0) + db_rt_before_render
34
34
  runtime = super
@@ -42,9 +42,8 @@ module ActiveRecord
42
42
 
43
43
  def append_info_to_payload(payload)
44
44
  super
45
- if ActiveRecord::Base.connected?
46
- payload[:db_runtime] = (db_runtime || 0) + ActiveRecord::LogSubscriber.reset_runtime
47
- end
45
+
46
+ payload[:db_runtime] = (db_runtime || 0) + ActiveRecord::LogSubscriber.reset_runtime
48
47
  end
49
48
  end
50
49
  end