activerecord 6.0.4.7 → 6.1.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1199 -777
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_record/aggregations.rb +5 -5
  6. data/lib/active_record/association_relation.rb +30 -12
  7. data/lib/active_record/associations/alias_tracker.rb +19 -15
  8. data/lib/active_record/associations/association.rb +49 -26
  9. data/lib/active_record/associations/association_scope.rb +18 -20
  10. data/lib/active_record/associations/belongs_to_association.rb +23 -10
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  12. data/lib/active_record/associations/builder/association.rb +32 -5
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +32 -18
  20. data/lib/active_record/associations/collection_proxy.rb +12 -5
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -2
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +37 -21
  26. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +63 -49
  28. data/lib/active_record/associations/preloader/association.rb +14 -8
  29. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  30. data/lib/active_record/associations/preloader.rb +5 -3
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations.rb +118 -11
  33. data/lib/active_record/attribute_assignment.rb +10 -8
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  35. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  36. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  37. data/lib/active_record/attribute_methods/query.rb +3 -6
  38. data/lib/active_record/attribute_methods/read.rb +8 -11
  39. data/lib/active_record/attribute_methods/serialization.rb +11 -5
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  41. data/lib/active_record/attribute_methods/write.rb +12 -20
  42. data/lib/active_record/attribute_methods.rb +64 -54
  43. data/lib/active_record/attributes.rb +33 -8
  44. data/lib/active_record/autosave_association.rb +47 -30
  45. data/lib/active_record/base.rb +2 -14
  46. data/lib/active_record/callbacks.rb +152 -22
  47. data/lib/active_record/coders/yaml_column.rb +24 -2
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -23
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -35
  53. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +114 -26
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +92 -33
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +52 -76
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
  61. data/lib/active_record/connection_adapters/column.rb +15 -1
  62. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  63. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +24 -24
  65. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  67. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  69. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  70. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -4
  71. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  73. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  74. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  75. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +14 -53
  77. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  78. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  80. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
  87. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  88. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  89. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  90. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  91. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -64
  92. data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
  93. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  94. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +32 -5
  95. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  96. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  97. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
  98. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
  99. data/lib/active_record/connection_adapters.rb +52 -0
  100. data/lib/active_record/connection_handling.rb +218 -71
  101. data/lib/active_record/core.rb +271 -60
  102. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  103. data/lib/active_record/database_configurations/database_config.rb +52 -9
  104. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  105. data/lib/active_record/database_configurations/url_config.rb +15 -40
  106. data/lib/active_record/database_configurations.rb +125 -85
  107. data/lib/active_record/delegated_type.rb +209 -0
  108. data/lib/active_record/destroy_association_async_job.rb +36 -0
  109. data/lib/active_record/enum.rb +69 -34
  110. data/lib/active_record/errors.rb +47 -12
  111. data/lib/active_record/explain.rb +9 -4
  112. data/lib/active_record/explain_subscriber.rb +1 -1
  113. data/lib/active_record/fixture_set/file.rb +10 -17
  114. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  115. data/lib/active_record/fixture_set/render_context.rb +1 -1
  116. data/lib/active_record/fixture_set/table_row.rb +2 -2
  117. data/lib/active_record/fixtures.rb +58 -9
  118. data/lib/active_record/gem_version.rb +3 -3
  119. data/lib/active_record/inheritance.rb +40 -18
  120. data/lib/active_record/insert_all.rb +38 -5
  121. data/lib/active_record/integration.rb +3 -5
  122. data/lib/active_record/internal_metadata.rb +18 -7
  123. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  124. data/lib/active_record/locking/optimistic.rb +24 -17
  125. data/lib/active_record/locking/pessimistic.rb +6 -2
  126. data/lib/active_record/log_subscriber.rb +27 -8
  127. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  128. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  129. data/lib/active_record/middleware/database_selector.rb +4 -1
  130. data/lib/active_record/migration/command_recorder.rb +47 -27
  131. data/lib/active_record/migration/compatibility.rb +72 -18
  132. data/lib/active_record/migration.rb +114 -84
  133. data/lib/active_record/model_schema.rb +89 -14
  134. data/lib/active_record/nested_attributes.rb +2 -3
  135. data/lib/active_record/no_touching.rb +1 -1
  136. data/lib/active_record/persistence.rb +50 -45
  137. data/lib/active_record/query_cache.rb +15 -5
  138. data/lib/active_record/querying.rb +11 -6
  139. data/lib/active_record/railtie.rb +64 -44
  140. data/lib/active_record/railties/console_sandbox.rb +2 -4
  141. data/lib/active_record/railties/databases.rake +279 -101
  142. data/lib/active_record/readonly_attributes.rb +4 -0
  143. data/lib/active_record/reflection.rb +60 -44
  144. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  145. data/lib/active_record/relation/batches.rb +38 -31
  146. data/lib/active_record/relation/calculations.rb +104 -43
  147. data/lib/active_record/relation/finder_methods.rb +44 -14
  148. data/lib/active_record/relation/from_clause.rb +1 -1
  149. data/lib/active_record/relation/merger.rb +20 -23
  150. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  151. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  152. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  153. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  154. data/lib/active_record/relation/predicate_builder.rb +61 -38
  155. data/lib/active_record/relation/query_methods.rb +324 -196
  156. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  157. data/lib/active_record/relation/spawn_methods.rb +8 -7
  158. data/lib/active_record/relation/where_clause.rb +111 -61
  159. data/lib/active_record/relation.rb +100 -81
  160. data/lib/active_record/result.rb +41 -33
  161. data/lib/active_record/runtime_registry.rb +2 -2
  162. data/lib/active_record/sanitization.rb +6 -17
  163. data/lib/active_record/schema_dumper.rb +34 -4
  164. data/lib/active_record/schema_migration.rb +2 -8
  165. data/lib/active_record/scoping/default.rb +1 -3
  166. data/lib/active_record/scoping/named.rb +1 -17
  167. data/lib/active_record/secure_token.rb +16 -8
  168. data/lib/active_record/serialization.rb +5 -3
  169. data/lib/active_record/signed_id.rb +116 -0
  170. data/lib/active_record/statement_cache.rb +20 -4
  171. data/lib/active_record/store.rb +8 -3
  172. data/lib/active_record/suppressor.rb +2 -2
  173. data/lib/active_record/table_metadata.rb +42 -51
  174. data/lib/active_record/tasks/database_tasks.rb +140 -113
  175. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  176. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  177. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  178. data/lib/active_record/test_databases.rb +5 -4
  179. data/lib/active_record/test_fixtures.rb +79 -31
  180. data/lib/active_record/timestamp.rb +4 -6
  181. data/lib/active_record/touch_later.rb +21 -21
  182. data/lib/active_record/transactions.rb +19 -66
  183. data/lib/active_record/type/serialized.rb +6 -2
  184. data/lib/active_record/type.rb +8 -1
  185. data/lib/active_record/type_caster/connection.rb +0 -1
  186. data/lib/active_record/type_caster/map.rb +8 -5
  187. data/lib/active_record/validations/associated.rb +1 -1
  188. data/lib/active_record/validations/numericality.rb +35 -0
  189. data/lib/active_record/validations/uniqueness.rb +24 -4
  190. data/lib/active_record/validations.rb +1 -0
  191. data/lib/active_record.rb +7 -14
  192. data/lib/arel/attributes/attribute.rb +4 -0
  193. data/lib/arel/collectors/bind.rb +5 -0
  194. data/lib/arel/collectors/composite.rb +8 -0
  195. data/lib/arel/collectors/sql_string.rb +7 -0
  196. data/lib/arel/collectors/substitute_binds.rb +7 -0
  197. data/lib/arel/nodes/binary.rb +82 -8
  198. data/lib/arel/nodes/bind_param.rb +8 -0
  199. data/lib/arel/nodes/casted.rb +21 -9
  200. data/lib/arel/nodes/equality.rb +6 -9
  201. data/lib/arel/nodes/grouping.rb +3 -0
  202. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  203. data/lib/arel/nodes/in.rb +8 -1
  204. data/lib/arel/nodes/infix_operation.rb +13 -1
  205. data/lib/arel/nodes/join_source.rb +1 -1
  206. data/lib/arel/nodes/node.rb +7 -6
  207. data/lib/arel/nodes/ordering.rb +27 -0
  208. data/lib/arel/nodes/sql_literal.rb +3 -0
  209. data/lib/arel/nodes/table_alias.rb +7 -3
  210. data/lib/arel/nodes/unary.rb +0 -1
  211. data/lib/arel/nodes.rb +3 -1
  212. data/lib/arel/predications.rb +12 -18
  213. data/lib/arel/select_manager.rb +1 -2
  214. data/lib/arel/table.rb +13 -5
  215. data/lib/arel/visitors/dot.rb +14 -2
  216. data/lib/arel/visitors/mysql.rb +11 -1
  217. data/lib/arel/visitors/postgresql.rb +15 -4
  218. data/lib/arel/visitors/to_sql.rb +89 -78
  219. data/lib/arel/visitors.rb +0 -7
  220. data/lib/arel.rb +5 -13
  221. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  222. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  223. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  224. data/lib/rails/generators/active_record/migration.rb +6 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  226. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  227. metadata +26 -26
  228. data/lib/active_record/advisory_lock_base.rb +0 -18
  229. data/lib/active_record/attribute_decorators.rb +0 -88
  230. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  231. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  232. data/lib/active_record/define_callbacks.rb +0 -22
  233. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  234. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  235. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  236. data/lib/arel/attributes.rb +0 -22
  237. data/lib/arel/visitors/depth_first.rb +0 -203
  238. data/lib/arel/visitors/ibm_db.rb +0 -34
  239. data/lib/arel/visitors/informix.rb +0 -62
  240. data/lib/arel/visitors/mssql.rb +0 -156
  241. data/lib/arel/visitors/oracle.rb +0 -158
  242. data/lib/arel/visitors/oracle12.rb +0 -65
  243. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/enumerable"
3
4
  require "active_support/core_ext/hash/indifferent_access"
4
5
  require "active_support/core_ext/string/filters"
5
6
  require "active_support/parameter_filter"
@@ -25,6 +26,18 @@ module ActiveRecord
25
26
  # their relevant queries. Defaults to false.
26
27
  mattr_accessor :verbose_query_logs, instance_writer: false, default: false
27
28
 
29
+ ##
30
+ # :singleton-method:
31
+ #
32
+ # Specifies the names of the queues used by background jobs.
33
+ mattr_accessor :queues, instance_accessor: false, default: {}
34
+
35
+ ##
36
+ # :singleton-method:
37
+ #
38
+ # Specifies the job used to destroy associations in the background
39
+ class_attribute :destroy_association_async_job, instance_writer: false, instance_predicate: false, default: false
40
+
28
41
  ##
29
42
  # Contains the database configuration - as is typically stored in config/database.yml -
30
43
  # as an ActiveRecord::DatabaseConfigurations object.
@@ -43,9 +56,9 @@ module ActiveRecord
43
56
  #
44
57
  # #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
45
58
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
46
- # @spec_name="primary", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}>,
59
+ # @name="primary", @config={adapter: "sqlite3", database: "db/development.sqlite3"}>,
47
60
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
48
- # @spec_name="primary", @config={"adapter"=>"mysql2", "database"=>"db/production.sqlite3"}>
61
+ # @name="primary", @config={adapter: "sqlite3", database: "db/production.sqlite3"}>
49
62
  # ]>
50
63
  def self.configurations=(config)
51
64
  @@configurations = ActiveRecord::DatabaseConfigurations.new(config)
@@ -80,14 +93,6 @@ module ActiveRecord
80
93
  # scope being ignored is error-worthy, rather than a warning.
81
94
  mattr_accessor :error_on_ignored_order, instance_writer: false, default: false
82
95
 
83
- # :singleton-method:
84
- # Specify the behavior for unsafe raw query methods. Values are as follows
85
- # deprecated - Warnings are logged when unsafe raw SQL is passed to
86
- # query methods.
87
- # disabled - Unsafe raw SQL passed to query methods results in
88
- # UnknownAttributeReference exception.
89
- mattr_accessor :allow_unsafe_raw_sql, instance_writer: false, default: :deprecated
90
-
91
96
  ##
92
97
  # :singleton-method:
93
98
  # Specify whether or not to use timestamps for migration versions
@@ -103,7 +108,7 @@ module ActiveRecord
103
108
 
104
109
  ##
105
110
  # :singleton-method:
106
- # Specifies which database schemas to dump when calling db:structure:dump.
111
+ # Specifies which database schemas to dump when calling db:schema:dump.
107
112
  # If the value is :schema_search_path (the default), any schemas listed in
108
113
  # schema_search_path are dumped. Use :all to dump all schemas regardless
109
114
  # of schema_search_path, or a string of comma separated schemas for a
@@ -118,29 +123,197 @@ module ActiveRecord
118
123
  # potentially cause memory bloat.
119
124
  mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
120
125
 
126
+ ##
127
+ # :singleton-method:
128
+ # Show a warning when Rails couldn't parse your database.yml
129
+ # for multiple databases.
130
+ mattr_accessor :suppress_multiple_database_warning, instance_writer: false, default: false
131
+
121
132
  mattr_accessor :maintain_test_schema, instance_accessor: false
122
133
 
123
- mattr_accessor :belongs_to_required_by_default, instance_accessor: false
134
+ class_attribute :belongs_to_required_by_default, instance_accessor: false
135
+
136
+ ##
137
+ # :singleton-method:
138
+ # Set the application to log or raise when an association violates strict loading.
139
+ # Defaults to :raise.
140
+ mattr_accessor :action_on_strict_loading_violation, instance_accessor: false, default: :raise
124
141
 
125
- mattr_accessor :connection_handlers, instance_accessor: false, default: {}
142
+ class_attribute :strict_loading_by_default, instance_accessor: false, default: false
126
143
 
127
144
  mattr_accessor :writing_role, instance_accessor: false, default: :writing
128
145
 
129
146
  mattr_accessor :reading_role, instance_accessor: false, default: :reading
130
147
 
148
+ mattr_accessor :has_many_inversing, instance_accessor: false, default: false
149
+
131
150
  class_attribute :default_connection_handler, instance_writer: false
132
151
 
152
+ class_attribute :default_role, instance_writer: false
153
+
154
+ class_attribute :default_shard, instance_writer: false
155
+
156
+ mattr_accessor :legacy_connection_handling, instance_writer: false, default: true
157
+
158
+ # Application configurable boolean that instructs the YAML Coder to use
159
+ # an unsafe load if set to true.
160
+ mattr_accessor :use_yaml_unsafe_load, instance_writer: false, default: false
161
+
162
+ # Application configurable array that provides additional permitted classes
163
+ # to Psych safe_load in the YAML Coder
164
+ mattr_accessor :yaml_column_permitted_classes, instance_writer: false, default: [Symbol]
165
+
166
+ ##
167
+ # :singleton-method:
168
+ # Application configurable boolean that denotes whether or not to raise
169
+ # an exception when the PostgreSQLAdapter is provided with an integer that is
170
+ # wider than signed 64bit representation
171
+ mattr_accessor :raise_int_wider_than_64bit, instance_writer: false, default: true
172
+
133
173
  self.filter_attributes = []
134
174
 
135
175
  def self.connection_handler
136
- Thread.current.thread_variable_get("ar_connection_handler") || default_connection_handler
176
+ Thread.current.thread_variable_get(:ar_connection_handler) || default_connection_handler
137
177
  end
138
178
 
139
179
  def self.connection_handler=(handler)
140
- Thread.current.thread_variable_set("ar_connection_handler", handler)
180
+ Thread.current.thread_variable_set(:ar_connection_handler, handler)
181
+ end
182
+
183
+ def self.connection_handlers
184
+ unless legacy_connection_handling
185
+ raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
186
+ end
187
+
188
+ @@connection_handlers ||= {}
189
+ end
190
+
191
+ def self.connection_handlers=(handlers)
192
+ unless legacy_connection_handling
193
+ raise NotImplementedError, "The new connection handling does not setting support multiple connection handlers."
194
+ end
195
+
196
+ @@connection_handlers = handlers
197
+ end
198
+
199
+ # Returns the symbol representing the current connected role.
200
+ #
201
+ # ActiveRecord::Base.connected_to(role: :writing) do
202
+ # ActiveRecord::Base.current_role #=> :writing
203
+ # end
204
+ #
205
+ # ActiveRecord::Base.connected_to(role: :reading) do
206
+ # ActiveRecord::Base.current_role #=> :reading
207
+ # end
208
+ def self.current_role
209
+ if ActiveRecord::Base.legacy_connection_handling
210
+ connection_handlers.key(connection_handler) || default_role
211
+ else
212
+ connected_to_stack.reverse_each do |hash|
213
+ return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
214
+ return hash[:role] if hash[:role] && hash[:klasses].include?(connection_classes)
215
+ end
216
+
217
+ default_role
218
+ end
219
+ end
220
+
221
+ # Returns the symbol representing the current connected shard.
222
+ #
223
+ # ActiveRecord::Base.connected_to(role: :reading) do
224
+ # ActiveRecord::Base.current_shard #=> :default
225
+ # end
226
+ #
227
+ # ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
228
+ # ActiveRecord::Base.current_shard #=> :one
229
+ # end
230
+ def self.current_shard
231
+ connected_to_stack.reverse_each do |hash|
232
+ return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
233
+ return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_classes)
234
+ end
235
+
236
+ default_shard
237
+ end
238
+
239
+ # Returns the symbol representing the current setting for
240
+ # preventing writes.
241
+ #
242
+ # ActiveRecord::Base.connected_to(role: :reading) do
243
+ # ActiveRecord::Base.current_preventing_writes #=> true
244
+ # end
245
+ #
246
+ # ActiveRecord::Base.connected_to(role: :writing) do
247
+ # ActiveRecord::Base.current_preventing_writes #=> false
248
+ # end
249
+ def self.current_preventing_writes
250
+ if legacy_connection_handling
251
+ connection_handler.prevent_writes
252
+ else
253
+ connected_to_stack.reverse_each do |hash|
254
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
255
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_classes)
256
+ end
257
+
258
+ false
259
+ end
260
+ end
261
+
262
+ def self.connected_to_stack # :nodoc:
263
+ if connected_to_stack = Thread.current.thread_variable_get(:ar_connected_to_stack)
264
+ connected_to_stack
265
+ else
266
+ connected_to_stack = Concurrent::Array.new
267
+ Thread.current.thread_variable_set(:ar_connected_to_stack, connected_to_stack)
268
+ connected_to_stack
269
+ end
270
+ end
271
+
272
+ def self.connection_class=(b) # :nodoc:
273
+ @connection_class = b
274
+ end
275
+
276
+ def self.connection_class # :nodoc
277
+ @connection_class ||= false
278
+ end
279
+
280
+ def self.connection_class? # :nodoc:
281
+ self.connection_class
282
+ end
283
+
284
+ def self.connection_classes # :nodoc:
285
+ klass = self
286
+
287
+ until klass == Base
288
+ break if klass.connection_class?
289
+ klass = klass.superclass
290
+ end
291
+
292
+ klass
293
+ end
294
+
295
+ def self.allow_unsafe_raw_sql # :nodoc:
296
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql is deprecated and will be removed in Rails 7.0")
297
+ end
298
+
299
+ def self.allow_unsafe_raw_sql=(value) # :nodoc:
300
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql= is deprecated and will be removed in Rails 7.0")
141
301
  end
142
302
 
143
303
  self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
304
+ self.default_role = writing_role
305
+ self.default_shard = :default
306
+
307
+ def self.strict_loading_violation!(owner:, reflection:) # :nodoc:
308
+ case action_on_strict_loading_violation
309
+ when :raise
310
+ message = "`#{owner}` is marked for strict_loading. The `#{reflection.klass}` association named `:#{reflection.name}` cannot be lazily loaded."
311
+ raise ActiveRecord::StrictLoadingViolationError.new(message)
312
+ when :log
313
+ name = "strict_loading_violation.active_record"
314
+ ActiveSupport::Notifications.instrument(name, owner: owner, reflection: reflection)
315
+ end
316
+ end
144
317
  end
145
318
 
146
319
  module ClassMethods
@@ -151,16 +324,20 @@ module ActiveRecord
151
324
  def inherited(child_class) # :nodoc:
152
325
  # initialize cache at class definition for thread safety
153
326
  child_class.initialize_find_by_cache
327
+ unless child_class.base_class?
328
+ klass = self
329
+ until klass.base_class?
330
+ klass.initialize_find_by_cache
331
+ klass = klass.superclass
332
+ end
333
+ end
154
334
  super
155
335
  end
156
336
 
157
337
  def find(*ids) # :nodoc:
158
338
  # We don't have cache keys for this stuff yet
159
339
  return super unless ids.length == 1
160
- return super if block_given? ||
161
- primary_key.nil? ||
162
- scope_attributes? ||
163
- columns_hash.key?(inheritance_column) && !base_class?
340
+ return super if block_given? || primary_key.nil? || scope_attributes?
164
341
 
165
342
  id = ids.first
166
343
 
@@ -172,36 +349,47 @@ module ActiveRecord
172
349
  where(key => params.bind).limit(1)
173
350
  }
174
351
 
175
- record = statement.execute([id], connection)&.first
176
- unless record
177
- raise RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id)
178
- end
179
- record
352
+ statement.execute([id], connection).first ||
353
+ raise(RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id))
180
354
  end
181
355
 
182
356
  def find_by(*args) # :nodoc:
183
- return super if scope_attributes? || reflect_on_all_aggregations.any? ||
184
- columns_hash.key?(inheritance_column) && !base_class?
357
+ return super if scope_attributes?
185
358
 
186
359
  hash = args.first
360
+ return super unless Hash === hash
187
361
 
188
- return super if !(Hash === hash) || hash.values.any? { |v|
189
- StatementCache.unsupported_value?(v)
190
- }
362
+ hash = hash.each_with_object({}) do |(key, value), h|
363
+ key = key.to_s
364
+ key = attribute_aliases[key] || key
191
365
 
192
- # We can't cache Post.find_by(author: david) ...yet
193
- return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
366
+ return super if reflect_on_aggregation(key)
194
367
 
195
- keys = hash.keys
368
+ reflection = _reflect_on_association(key)
369
+
370
+ if !reflection
371
+ value = value.id if value.respond_to?(:id)
372
+ elsif reflection.belongs_to? && !reflection.polymorphic?
373
+ key = reflection.join_foreign_key
374
+ pkey = reflection.join_primary_key
375
+ value = value.public_send(pkey) if value.respond_to?(pkey)
376
+ end
377
+
378
+ if !columns_hash.key?(key) || StatementCache.unsupported_value?(value)
379
+ return super
380
+ end
196
381
 
382
+ h[key] = value
383
+ end
384
+
385
+ keys = hash.keys
197
386
  statement = cached_find_by_statement(keys) { |params|
198
- wheres = keys.each_with_object({}) { |param, o|
199
- o[param] = params.bind
200
- }
387
+ wheres = keys.index_with { params.bind }
201
388
  where(wheres).limit(1)
202
389
  }
390
+
203
391
  begin
204
- statement.execute(hash.values, connection)&.first
392
+ statement.execute(hash.values, connection).first
205
393
  rescue TypeError
206
394
  raise ActiveRecord::StatementInvalid
207
395
  end
@@ -235,7 +423,21 @@ module ActiveRecord
235
423
  end
236
424
 
237
425
  # Specifies columns which shouldn't be exposed while calling +#inspect+.
238
- attr_writer :filter_attributes
426
+ def filter_attributes=(filter_attributes)
427
+ @inspection_filter = nil
428
+ @filter_attributes = filter_attributes
429
+ end
430
+
431
+ def inspection_filter # :nodoc:
432
+ if defined?(@filter_attributes)
433
+ @inspection_filter ||= begin
434
+ mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
435
+ ActiveSupport::ParameterFilter.new(@filter_attributes, mask: mask)
436
+ end
437
+ else
438
+ superclass.inspection_filter
439
+ end
440
+ end
239
441
 
240
442
  # Returns a string like 'Post(id:integer, title:string, body:text)'
241
443
  def inspect # :nodoc:
@@ -264,14 +466,13 @@ module ActiveRecord
264
466
  # scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
265
467
  # end
266
468
  def arel_table # :nodoc:
267
- @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
469
+ @arel_table ||= Arel::Table.new(table_name, klass: self)
268
470
  end
269
471
 
270
472
  def arel_attribute(name, table = arel_table) # :nodoc:
271
- name = name.to_s
272
- name = attribute_aliases[name] || name
273
473
  table[name]
274
474
  end
475
+ deprecate :arel_attribute
275
476
 
276
477
  def predicate_builder # :nodoc:
277
478
  @predicate_builder ||= PredicateBuilder.new(table_metadata)
@@ -399,9 +600,9 @@ module ActiveRecord
399
600
  _run_initialize_callbacks
400
601
 
401
602
  @new_record = true
603
+ @previously_new_record = false
402
604
  @destroyed = false
403
605
  @_start_transaction_state = nil
404
- @transaction_state = nil
405
606
 
406
607
  super
407
608
  end
@@ -461,7 +662,6 @@ module ActiveRecord
461
662
 
462
663
  # Returns +true+ if the attributes hash has been frozen.
463
664
  def frozen?
464
- sync_with_transaction_state if @transaction_state&.finalized?
465
665
  @attributes.frozen?
466
666
  end
467
667
 
@@ -482,12 +682,27 @@ module ActiveRecord
482
682
  false
483
683
  end
484
684
 
485
- # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
486
- # attributes will be marked as read only since they cannot be saved.
685
+ # Returns +true+ if the record is read only.
487
686
  def readonly?
488
687
  @readonly
489
688
  end
490
689
 
690
+ # Returns +true+ if the record is in strict_loading mode.
691
+ def strict_loading?
692
+ @strict_loading
693
+ end
694
+
695
+ # Sets the record to strict_loading mode. This will raise an error
696
+ # if the record tries to lazily load an association.
697
+ #
698
+ # user = User.first
699
+ # user.strict_loading!
700
+ # user.comments.to_a
701
+ # => ActiveRecord::StrictLoadingViolationError
702
+ def strict_loading!
703
+ @strict_loading = true
704
+ end
705
+
491
706
  # Marks this record as read only.
492
707
  def readonly!
493
708
  @readonly = true
@@ -503,15 +718,8 @@ module ActiveRecord
503
718
  # allocated but not initialized.
504
719
  inspection = if defined?(@attributes) && @attributes
505
720
  self.class.attribute_names.collect do |name|
506
- if has_attribute?(name)
507
- attr = _read_attribute(name)
508
- value = if attr.nil?
509
- attr.inspect
510
- else
511
- attr = format_for_inspect(attr)
512
- inspection_filter.filter_param(name, attr)
513
- end
514
- "#{name}: #{value}"
721
+ if _has_attribute?(name)
722
+ "#{name}: #{attribute_for_inspect(name)}"
515
723
  end
516
724
  end.compact.join(", ")
517
725
  else
@@ -527,7 +735,7 @@ module ActiveRecord
527
735
  return super if custom_inspect_method_defined?
528
736
  pp.object_address_group(self) do
529
737
  if defined?(@attributes) && @attributes
530
- attr_names = self.class.attribute_names.select { |name| has_attribute?(name) }
738
+ attr_names = self.class.attribute_names.select { |name| _has_attribute?(name) }
531
739
  pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
532
740
  pp.breakable " "
533
741
  pp.group(1) do
@@ -548,7 +756,12 @@ module ActiveRecord
548
756
 
549
757
  # Returns a hash of the given methods with their names as keys and returned values as values.
550
758
  def slice(*methods)
551
- Hash[methods.flatten.map! { |method| [method, public_send(method)] }].with_indifferent_access
759
+ methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
760
+ end
761
+
762
+ # Returns an array of the values returned by the given methods.
763
+ def values_at(*methods)
764
+ methods.flatten.map! { |method| public_send(method) }
552
765
  end
553
766
 
554
767
  private
@@ -567,11 +780,12 @@ module ActiveRecord
567
780
  def init_internals
568
781
  @primary_key = self.class.primary_key
569
782
  @readonly = false
783
+ @previously_new_record = false
570
784
  @destroyed = false
571
785
  @marked_for_destruction = false
572
786
  @destroyed_by_association = nil
573
787
  @_start_transaction_state = nil
574
- @transaction_state = nil
788
+ @strict_loading = self.class.strict_loading_by_default
575
789
 
576
790
  self.class.define_attribute_methods
577
791
  end
@@ -591,10 +805,7 @@ module ActiveRecord
591
805
  private_constant :InspectionMask
592
806
 
593
807
  def inspection_filter
594
- @inspection_filter ||= begin
595
- mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
596
- ActiveSupport::ParameterFilter.new(self.class.filter_attributes, mask: mask)
597
- end
808
+ self.class.inspection_filter
598
809
  end
599
810
  end
600
811
  end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+ require "active_support/core_ext/enumerable"
5
+
6
+ module ActiveRecord
7
+ class DatabaseConfigurations
8
+ # Expands a connection string into a hash.
9
+ class ConnectionUrlResolver # :nodoc:
10
+ # == Example
11
+ #
12
+ # url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000"
13
+ # ConnectionUrlResolver.new(url).to_hash
14
+ # # => {
15
+ # adapter: "postgresql",
16
+ # host: "localhost",
17
+ # port: 9000,
18
+ # database: "foo_test",
19
+ # username: "foo",
20
+ # password: "bar",
21
+ # pool: "5",
22
+ # timeout: "3000"
23
+ # }
24
+ def initialize(url)
25
+ raise "Database URL cannot be empty" if url.blank?
26
+ @uri = uri_parser.parse(url)
27
+ @adapter = @uri.scheme && @uri.scheme.tr("-", "_")
28
+ @adapter = "postgresql" if @adapter == "postgres"
29
+
30
+ if @uri.opaque
31
+ @uri.opaque, @query = @uri.opaque.split("?", 2)
32
+ else
33
+ @query = @uri.query
34
+ end
35
+ end
36
+
37
+ # Converts the given URL to a full connection hash.
38
+ def to_hash
39
+ config = raw_config.compact_blank
40
+ config.map { |key, value| config[key] = uri_parser.unescape(value) if value.is_a? String }
41
+ config
42
+ end
43
+
44
+ private
45
+ attr_reader :uri
46
+
47
+ def uri_parser
48
+ @uri_parser ||= URI::Parser.new
49
+ end
50
+
51
+ # Converts the query parameters of the URI into a hash.
52
+ #
53
+ # "localhost?pool=5&reaping_frequency=2"
54
+ # # => { pool: "5", reaping_frequency: "2" }
55
+ #
56
+ # returns empty hash if no query present.
57
+ #
58
+ # "localhost"
59
+ # # => {}
60
+ def query_hash
61
+ Hash[(@query || "").split("&").map { |pair| pair.split("=", 2) }].symbolize_keys
62
+ end
63
+
64
+ def raw_config
65
+ if uri.opaque
66
+ query_hash.merge(
67
+ adapter: @adapter,
68
+ database: uri.opaque
69
+ )
70
+ else
71
+ query_hash.merge(
72
+ adapter: @adapter,
73
+ username: uri.user,
74
+ password: uri.password,
75
+ port: uri.port,
76
+ database: database_from_path,
77
+ host: uri.hostname
78
+ )
79
+ end
80
+ end
81
+
82
+ # Returns name of the database.
83
+ def database_from_path
84
+ if @adapter == "sqlite3"
85
+ # 'sqlite3:/foo' is absolute, because that makes sense. The
86
+ # corresponding relative version, 'sqlite3:foo', is handled
87
+ # elsewhere, as an "opaque".
88
+
89
+ uri.path
90
+ else
91
+ # Only SQLite uses a filename as the "database" name; for
92
+ # anything else, a leading slash would be silly.
93
+
94
+ uri.path.delete_prefix("/")
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -6,32 +6,75 @@ module ActiveRecord
6
6
  # UrlConfig respectively. It will never return a DatabaseConfig object,
7
7
  # as this is the parent class for the types of database configuration objects.
8
8
  class DatabaseConfig # :nodoc:
9
- attr_reader :env_name, :spec_name
9
+ attr_reader :env_name, :name
10
10
 
11
- def initialize(env_name, spec_name)
11
+ attr_accessor :owner_name
12
+
13
+ def initialize(env_name, name)
12
14
  @env_name = env_name
13
- @spec_name = spec_name
15
+ @name = name
14
16
  end
15
17
 
16
- def replica?
18
+ def spec_name
19
+ @name
20
+ end
21
+ deprecate spec_name: "please use name instead"
22
+
23
+ def config
17
24
  raise NotImplementedError
18
25
  end
19
26
 
20
- def migrations_paths
27
+ def adapter_method
28
+ "#{adapter}_connection"
29
+ end
30
+
31
+ def host
32
+ raise NotImplementedError
33
+ end
34
+
35
+ def database
21
36
  raise NotImplementedError
22
37
  end
23
38
 
24
- def url_config?
25
- false
39
+ def _database=(database)
40
+ raise NotImplementedError
41
+ end
42
+
43
+ def adapter
44
+ raise NotImplementedError
26
45
  end
27
46
 
28
- def to_legacy_hash
29
- { env_name => config }
47
+ def pool
48
+ raise NotImplementedError
49
+ end
50
+
51
+ def checkout_timeout
52
+ raise NotImplementedError
53
+ end
54
+
55
+ def reaping_frequency
56
+ raise NotImplementedError
57
+ end
58
+
59
+ def idle_timeout
60
+ raise NotImplementedError
61
+ end
62
+
63
+ def replica?
64
+ raise NotImplementedError
65
+ end
66
+
67
+ def migrations_paths
68
+ raise NotImplementedError
30
69
  end
31
70
 
32
71
  def for_current_env?
33
72
  env_name == ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
34
73
  end
74
+
75
+ def schema_cache_path
76
+ raise NotImplementedError
77
+ end
35
78
  end
36
79
  end
37
80
  end