activerecord 6.0.1 → 6.1.7

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.

Files changed (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1314 -633
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_record/aggregations.rb +5 -6
  6. data/lib/active_record/association_relation.rb +26 -15
  7. data/lib/active_record/associations/alias_tracker.rb +19 -16
  8. data/lib/active_record/associations/association.rb +55 -37
  9. data/lib/active_record/associations/association_scope.rb +19 -15
  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 -3
  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 +38 -13
  20. data/lib/active_record/associations/collection_proxy.rb +14 -7
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -3
  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 +39 -16
  26. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  27. data/lib/active_record/associations/join_dependency.rb +73 -42
  28. data/lib/active_record/associations/preloader/association.rb +49 -25
  29. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +12 -7
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +119 -12
  34. data/lib/active_record/attribute_assignment.rb +10 -9
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
  36. data/lib/active_record/attribute_methods/dirty.rb +3 -13
  37. data/lib/active_record/attribute_methods/primary_key.rb +6 -4
  38. data/lib/active_record/attribute_methods/query.rb +3 -6
  39. data/lib/active_record/attribute_methods/read.rb +8 -12
  40. data/lib/active_record/attribute_methods/serialization.rb +11 -6
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  42. data/lib/active_record/attribute_methods/write.rb +12 -21
  43. data/lib/active_record/attribute_methods.rb +64 -54
  44. data/lib/active_record/attributes.rb +33 -9
  45. data/lib/active_record/autosave_association.rb +56 -41
  46. data/lib/active_record/base.rb +2 -14
  47. data/lib/active_record/callbacks.rb +153 -24
  48. data/lib/active_record/coders/yaml_column.rb +24 -3
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +190 -136
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -38
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -9
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +145 -52
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +63 -77
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +136 -111
  62. data/lib/active_record/connection_adapters/column.rb +15 -1
  63. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  64. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  65. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
  67. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  68. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  69. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
  70. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  71. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  72. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -13
  73. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  74. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
  75. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  76. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
  79. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  81. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  102. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql_adapter.rb +80 -66
  104. data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
  105. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  106. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
  107. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
  108. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  109. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
  110. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +57 -57
  111. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  112. data/lib/active_record/connection_adapters.rb +52 -0
  113. data/lib/active_record/connection_handling.rb +218 -87
  114. data/lib/active_record/core.rb +269 -68
  115. data/lib/active_record/counter_cache.rb +4 -1
  116. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  117. data/lib/active_record/database_configurations/database_config.rb +52 -9
  118. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  119. data/lib/active_record/database_configurations/url_config.rb +15 -41
  120. data/lib/active_record/database_configurations.rb +125 -85
  121. data/lib/active_record/delegated_type.rb +209 -0
  122. data/lib/active_record/destroy_association_async_job.rb +36 -0
  123. data/lib/active_record/dynamic_matchers.rb +2 -3
  124. data/lib/active_record/enum.rb +80 -38
  125. data/lib/active_record/errors.rb +47 -12
  126. data/lib/active_record/explain.rb +9 -5
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +10 -17
  129. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  130. data/lib/active_record/fixture_set/render_context.rb +1 -1
  131. data/lib/active_record/fixture_set/table_row.rb +2 -3
  132. data/lib/active_record/fixture_set/table_rows.rb +0 -1
  133. data/lib/active_record/fixtures.rb +58 -12
  134. data/lib/active_record/gem_version.rb +2 -2
  135. data/lib/active_record/inheritance.rb +40 -21
  136. data/lib/active_record/insert_all.rb +42 -9
  137. data/lib/active_record/integration.rb +3 -5
  138. data/lib/active_record/internal_metadata.rb +18 -7
  139. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  140. data/lib/active_record/locking/optimistic.rb +33 -18
  141. data/lib/active_record/locking/pessimistic.rb +6 -2
  142. data/lib/active_record/log_subscriber.rb +28 -9
  143. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  144. data/lib/active_record/middleware/database_selector/resolver.rb +6 -2
  145. data/lib/active_record/middleware/database_selector.rb +4 -2
  146. data/lib/active_record/migration/command_recorder.rb +53 -45
  147. data/lib/active_record/migration/compatibility.rb +75 -21
  148. data/lib/active_record/migration/join_table.rb +0 -1
  149. data/lib/active_record/migration.rb +115 -85
  150. data/lib/active_record/model_schema.rb +117 -15
  151. data/lib/active_record/nested_attributes.rb +2 -5
  152. data/lib/active_record/no_touching.rb +1 -1
  153. data/lib/active_record/null_relation.rb +0 -1
  154. data/lib/active_record/persistence.rb +50 -46
  155. data/lib/active_record/query_cache.rb +15 -5
  156. data/lib/active_record/querying.rb +12 -7
  157. data/lib/active_record/railtie.rb +65 -45
  158. data/lib/active_record/railties/console_sandbox.rb +2 -4
  159. data/lib/active_record/railties/databases.rake +280 -99
  160. data/lib/active_record/readonly_attributes.rb +4 -0
  161. data/lib/active_record/reflection.rb +77 -63
  162. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  163. data/lib/active_record/relation/batches.rb +38 -32
  164. data/lib/active_record/relation/calculations.rb +106 -45
  165. data/lib/active_record/relation/delegation.rb +9 -7
  166. data/lib/active_record/relation/finder_methods.rb +45 -16
  167. data/lib/active_record/relation/from_clause.rb +5 -1
  168. data/lib/active_record/relation/merger.rb +27 -26
  169. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  170. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  171. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  172. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  173. data/lib/active_record/relation/predicate_builder.rb +59 -40
  174. data/lib/active_record/relation/query_methods.rb +339 -188
  175. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  176. data/lib/active_record/relation/spawn_methods.rb +8 -8
  177. data/lib/active_record/relation/where_clause.rb +111 -62
  178. data/lib/active_record/relation.rb +116 -83
  179. data/lib/active_record/result.rb +41 -34
  180. data/lib/active_record/runtime_registry.rb +2 -2
  181. data/lib/active_record/sanitization.rb +6 -17
  182. data/lib/active_record/schema_dumper.rb +34 -4
  183. data/lib/active_record/schema_migration.rb +2 -8
  184. data/lib/active_record/scoping/default.rb +1 -4
  185. data/lib/active_record/scoping/named.rb +7 -18
  186. data/lib/active_record/scoping.rb +0 -1
  187. data/lib/active_record/secure_token.rb +16 -8
  188. data/lib/active_record/serialization.rb +5 -3
  189. data/lib/active_record/signed_id.rb +116 -0
  190. data/lib/active_record/statement_cache.rb +20 -4
  191. data/lib/active_record/store.rb +9 -4
  192. data/lib/active_record/suppressor.rb +2 -2
  193. data/lib/active_record/table_metadata.rb +42 -36
  194. data/lib/active_record/tasks/database_tasks.rb +140 -113
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
  197. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
  198. data/lib/active_record/test_databases.rb +5 -4
  199. data/lib/active_record/test_fixtures.rb +87 -20
  200. data/lib/active_record/timestamp.rb +4 -7
  201. data/lib/active_record/touch_later.rb +20 -21
  202. data/lib/active_record/transactions.rb +25 -72
  203. data/lib/active_record/type/adapter_specific_registry.rb +2 -5
  204. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  205. data/lib/active_record/type/serialized.rb +6 -3
  206. data/lib/active_record/type/time.rb +10 -0
  207. data/lib/active_record/type/type_map.rb +0 -1
  208. data/lib/active_record/type/unsigned_integer.rb +0 -1
  209. data/lib/active_record/type.rb +8 -2
  210. data/lib/active_record/type_caster/connection.rb +0 -1
  211. data/lib/active_record/type_caster/map.rb +8 -5
  212. data/lib/active_record/validations/associated.rb +1 -2
  213. data/lib/active_record/validations/numericality.rb +35 -0
  214. data/lib/active_record/validations/uniqueness.rb +24 -4
  215. data/lib/active_record/validations.rb +3 -3
  216. data/lib/active_record.rb +7 -13
  217. data/lib/arel/attributes/attribute.rb +4 -0
  218. data/lib/arel/collectors/bind.rb +5 -0
  219. data/lib/arel/collectors/composite.rb +8 -0
  220. data/lib/arel/collectors/sql_string.rb +7 -0
  221. data/lib/arel/collectors/substitute_binds.rb +7 -0
  222. data/lib/arel/nodes/binary.rb +82 -8
  223. data/lib/arel/nodes/bind_param.rb +8 -0
  224. data/lib/arel/nodes/casted.rb +21 -9
  225. data/lib/arel/nodes/equality.rb +6 -9
  226. data/lib/arel/nodes/grouping.rb +3 -0
  227. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  228. data/lib/arel/nodes/in.rb +8 -1
  229. data/lib/arel/nodes/infix_operation.rb +13 -1
  230. data/lib/arel/nodes/join_source.rb +1 -1
  231. data/lib/arel/nodes/node.rb +7 -6
  232. data/lib/arel/nodes/ordering.rb +27 -0
  233. data/lib/arel/nodes/sql_literal.rb +3 -0
  234. data/lib/arel/nodes/table_alias.rb +7 -3
  235. data/lib/arel/nodes/unary.rb +0 -1
  236. data/lib/arel/nodes.rb +3 -1
  237. data/lib/arel/predications.rb +17 -24
  238. data/lib/arel/select_manager.rb +1 -2
  239. data/lib/arel/table.rb +13 -5
  240. data/lib/arel/visitors/dot.rb +14 -3
  241. data/lib/arel/visitors/mysql.rb +11 -1
  242. data/lib/arel/visitors/postgresql.rb +15 -5
  243. data/lib/arel/visitors/sqlite.rb +0 -1
  244. data/lib/arel/visitors/to_sql.rb +89 -79
  245. data/lib/arel/visitors/visitor.rb +0 -1
  246. data/lib/arel/visitors.rb +0 -7
  247. data/lib/arel.rb +5 -9
  248. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  249. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  250. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  251. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  252. data/lib/rails/generators/active_record/migration.rb +6 -2
  253. data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
  254. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  255. metadata +30 -29
  256. data/lib/active_record/attribute_decorators.rb +0 -90
  257. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  258. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  259. data/lib/active_record/define_callbacks.rb +0 -22
  260. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  261. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  262. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  263. data/lib/arel/attributes.rb +0 -22
  264. data/lib/arel/visitors/depth_first.rb +0 -204
  265. data/lib/arel/visitors/ibm_db.rb +0 -34
  266. data/lib/arel/visitors/informix.rb +0 -62
  267. data/lib/arel/visitors/mssql.rb +0 -157
  268. data/lib/arel/visitors/oracle.rb +0 -159
  269. data/lib/arel/visitors/oracle12.rb +0 -66
  270. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -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,190 @@ 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
124
135
 
125
- mattr_accessor :connection_handlers, instance_accessor: false, default: {}
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
141
+
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
+
133
166
  self.filter_attributes = []
134
167
 
135
168
  def self.connection_handler
136
- Thread.current.thread_variable_get("ar_connection_handler") || default_connection_handler
169
+ Thread.current.thread_variable_get(:ar_connection_handler) || default_connection_handler
137
170
  end
138
171
 
139
172
  def self.connection_handler=(handler)
140
- Thread.current.thread_variable_set("ar_connection_handler", handler)
173
+ Thread.current.thread_variable_set(:ar_connection_handler, handler)
174
+ end
175
+
176
+ def self.connection_handlers
177
+ unless legacy_connection_handling
178
+ raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
179
+ end
180
+
181
+ @@connection_handlers ||= {}
182
+ end
183
+
184
+ def self.connection_handlers=(handlers)
185
+ unless legacy_connection_handling
186
+ raise NotImplementedError, "The new connection handling does not setting support multiple connection handlers."
187
+ end
188
+
189
+ @@connection_handlers = handlers
190
+ end
191
+
192
+ # Returns the symbol representing the current connected role.
193
+ #
194
+ # ActiveRecord::Base.connected_to(role: :writing) do
195
+ # ActiveRecord::Base.current_role #=> :writing
196
+ # end
197
+ #
198
+ # ActiveRecord::Base.connected_to(role: :reading) do
199
+ # ActiveRecord::Base.current_role #=> :reading
200
+ # end
201
+ def self.current_role
202
+ if ActiveRecord::Base.legacy_connection_handling
203
+ connection_handlers.key(connection_handler) || default_role
204
+ else
205
+ connected_to_stack.reverse_each do |hash|
206
+ return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
207
+ return hash[:role] if hash[:role] && hash[:klasses].include?(connection_classes)
208
+ end
209
+
210
+ default_role
211
+ end
212
+ end
213
+
214
+ # Returns the symbol representing the current connected shard.
215
+ #
216
+ # ActiveRecord::Base.connected_to(role: :reading) do
217
+ # ActiveRecord::Base.current_shard #=> :default
218
+ # end
219
+ #
220
+ # ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
221
+ # ActiveRecord::Base.current_shard #=> :one
222
+ # end
223
+ def self.current_shard
224
+ connected_to_stack.reverse_each do |hash|
225
+ return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
226
+ return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_classes)
227
+ end
228
+
229
+ default_shard
230
+ end
231
+
232
+ # Returns the symbol representing the current setting for
233
+ # preventing writes.
234
+ #
235
+ # ActiveRecord::Base.connected_to(role: :reading) do
236
+ # ActiveRecord::Base.current_preventing_writes #=> true
237
+ # end
238
+ #
239
+ # ActiveRecord::Base.connected_to(role: :writing) do
240
+ # ActiveRecord::Base.current_preventing_writes #=> false
241
+ # end
242
+ def self.current_preventing_writes
243
+ if legacy_connection_handling
244
+ connection_handler.prevent_writes
245
+ else
246
+ connected_to_stack.reverse_each do |hash|
247
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
248
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_classes)
249
+ end
250
+
251
+ false
252
+ end
253
+ end
254
+
255
+ def self.connected_to_stack # :nodoc:
256
+ if connected_to_stack = Thread.current.thread_variable_get(:ar_connected_to_stack)
257
+ connected_to_stack
258
+ else
259
+ connected_to_stack = Concurrent::Array.new
260
+ Thread.current.thread_variable_set(:ar_connected_to_stack, connected_to_stack)
261
+ connected_to_stack
262
+ end
263
+ end
264
+
265
+ def self.connection_class=(b) # :nodoc:
266
+ @connection_class = b
267
+ end
268
+
269
+ def self.connection_class # :nodoc
270
+ @connection_class ||= false
271
+ end
272
+
273
+ def self.connection_class? # :nodoc:
274
+ self.connection_class
275
+ end
276
+
277
+ def self.connection_classes # :nodoc:
278
+ klass = self
279
+
280
+ until klass == Base
281
+ break if klass.connection_class?
282
+ klass = klass.superclass
283
+ end
284
+
285
+ klass
286
+ end
287
+
288
+ def self.allow_unsafe_raw_sql # :nodoc:
289
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql is deprecated and will be removed in Rails 7.0")
290
+ end
291
+
292
+ def self.allow_unsafe_raw_sql=(value) # :nodoc:
293
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql= is deprecated and will be removed in Rails 7.0")
141
294
  end
142
295
 
143
296
  self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
297
+ self.default_role = writing_role
298
+ self.default_shard = :default
299
+
300
+ def self.strict_loading_violation!(owner:, reflection:) # :nodoc:
301
+ case action_on_strict_loading_violation
302
+ when :raise
303
+ message = "`#{owner}` is marked for strict_loading. The `#{reflection.klass}` association named `:#{reflection.name}` cannot be lazily loaded."
304
+ raise ActiveRecord::StrictLoadingViolationError.new(message)
305
+ when :log
306
+ name = "strict_loading_violation.active_record"
307
+ ActiveSupport::Notifications.instrument(name, owner: owner, reflection: reflection)
308
+ end
309
+ end
144
310
  end
145
311
 
146
312
  module ClassMethods
@@ -151,16 +317,20 @@ module ActiveRecord
151
317
  def inherited(child_class) # :nodoc:
152
318
  # initialize cache at class definition for thread safety
153
319
  child_class.initialize_find_by_cache
320
+ unless child_class.base_class?
321
+ klass = self
322
+ until klass.base_class?
323
+ klass.initialize_find_by_cache
324
+ klass = klass.superclass
325
+ end
326
+ end
154
327
  super
155
328
  end
156
329
 
157
330
  def find(*ids) # :nodoc:
158
331
  # We don't have cache keys for this stuff yet
159
332
  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?
333
+ return super if block_given? || primary_key.nil? || scope_attributes?
164
334
 
165
335
  id = ids.first
166
336
 
@@ -172,36 +342,47 @@ module ActiveRecord
172
342
  where(key => params.bind).limit(1)
173
343
  }
174
344
 
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
345
+ statement.execute([id], connection).first ||
346
+ raise(RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id))
180
347
  end
181
348
 
182
349
  def find_by(*args) # :nodoc:
183
- return super if scope_attributes? || reflect_on_all_aggregations.any? ||
184
- columns_hash.key?(inheritance_column) && !base_class?
350
+ return super if scope_attributes?
185
351
 
186
352
  hash = args.first
353
+ return super unless Hash === hash
187
354
 
188
- return super if !(Hash === hash) || hash.values.any? { |v|
189
- StatementCache.unsupported_value?(v)
190
- }
355
+ hash = hash.each_with_object({}) do |(key, value), h|
356
+ key = key.to_s
357
+ key = attribute_aliases[key] || key
191
358
 
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) }
359
+ return super if reflect_on_aggregation(key)
194
360
 
195
- keys = hash.keys
361
+ reflection = _reflect_on_association(key)
196
362
 
363
+ if !reflection
364
+ value = value.id if value.respond_to?(:id)
365
+ elsif reflection.belongs_to? && !reflection.polymorphic?
366
+ key = reflection.join_foreign_key
367
+ pkey = reflection.join_primary_key
368
+ value = value.public_send(pkey) if value.respond_to?(pkey)
369
+ end
370
+
371
+ if !columns_hash.key?(key) || StatementCache.unsupported_value?(value)
372
+ return super
373
+ end
374
+
375
+ h[key] = value
376
+ end
377
+
378
+ keys = hash.keys
197
379
  statement = cached_find_by_statement(keys) { |params|
198
- wheres = keys.each_with_object({}) { |param, o|
199
- o[param] = params.bind
200
- }
380
+ wheres = keys.index_with { params.bind }
201
381
  where(wheres).limit(1)
202
382
  }
383
+
203
384
  begin
204
- statement.execute(hash.values, connection)&.first
385
+ statement.execute(hash.values, connection).first
205
386
  rescue TypeError
206
387
  raise ActiveRecord::StatementInvalid
207
388
  end
@@ -235,7 +416,21 @@ module ActiveRecord
235
416
  end
236
417
 
237
418
  # Specifies columns which shouldn't be exposed while calling +#inspect+.
238
- attr_writer :filter_attributes
419
+ def filter_attributes=(filter_attributes)
420
+ @inspection_filter = nil
421
+ @filter_attributes = filter_attributes
422
+ end
423
+
424
+ def inspection_filter # :nodoc:
425
+ if defined?(@filter_attributes)
426
+ @inspection_filter ||= begin
427
+ mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
428
+ ActiveSupport::ParameterFilter.new(@filter_attributes, mask: mask)
429
+ end
430
+ else
431
+ superclass.inspection_filter
432
+ end
433
+ end
239
434
 
240
435
  # Returns a string like 'Post(id:integer, title:string, body:text)'
241
436
  def inspect # :nodoc:
@@ -264,14 +459,13 @@ module ActiveRecord
264
459
  # scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
265
460
  # end
266
461
  def arel_table # :nodoc:
267
- @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
462
+ @arel_table ||= Arel::Table.new(table_name, klass: self)
268
463
  end
269
464
 
270
465
  def arel_attribute(name, table = arel_table) # :nodoc:
271
- name = name.to_s
272
- name = attribute_aliases[name] || name
273
466
  table[name]
274
467
  end
468
+ deprecate :arel_attribute
275
469
 
276
470
  def predicate_builder # :nodoc:
277
471
  @predicate_builder ||= PredicateBuilder.new(table_metadata)
@@ -285,19 +479,17 @@ module ActiveRecord
285
479
  false
286
480
  end
287
481
 
288
- private
289
-
290
- def cached_find_by_statement(key, &block)
291
- cache = @find_by_statement_cache[connection.prepared_statements]
292
- cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
293
- end
482
+ def cached_find_by_statement(key, &block) # :nodoc:
483
+ cache = @find_by_statement_cache[connection.prepared_statements]
484
+ cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
485
+ end
294
486
 
487
+ private
295
488
  def relation
296
489
  relation = Relation.create(self)
297
490
 
298
491
  if finder_needs_type_condition? && !ignore_default_scope?
299
492
  relation.where!(type_condition)
300
- relation.create_with!(inheritance_column.to_s => sti_name)
301
493
  else
302
494
  relation
303
495
  end
@@ -401,9 +593,9 @@ module ActiveRecord
401
593
  _run_initialize_callbacks
402
594
 
403
595
  @new_record = true
596
+ @previously_new_record = false
404
597
  @destroyed = false
405
598
  @_start_transaction_state = nil
406
- @transaction_state = nil
407
599
 
408
600
  super
409
601
  end
@@ -463,7 +655,6 @@ module ActiveRecord
463
655
 
464
656
  # Returns +true+ if the attributes hash has been frozen.
465
657
  def frozen?
466
- sync_with_transaction_state if @transaction_state&.finalized?
467
658
  @attributes.frozen?
468
659
  end
469
660
 
@@ -484,12 +675,27 @@ module ActiveRecord
484
675
  false
485
676
  end
486
677
 
487
- # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
488
- # attributes will be marked as read only since they cannot be saved.
678
+ # Returns +true+ if the record is read only.
489
679
  def readonly?
490
680
  @readonly
491
681
  end
492
682
 
683
+ # Returns +true+ if the record is in strict_loading mode.
684
+ def strict_loading?
685
+ @strict_loading
686
+ end
687
+
688
+ # Sets the record to strict_loading mode. This will raise an error
689
+ # if the record tries to lazily load an association.
690
+ #
691
+ # user = User.first
692
+ # user.strict_loading!
693
+ # user.comments.to_a
694
+ # => ActiveRecord::StrictLoadingViolationError
695
+ def strict_loading!
696
+ @strict_loading = true
697
+ end
698
+
493
699
  # Marks this record as read only.
494
700
  def readonly!
495
701
  @readonly = true
@@ -505,15 +711,8 @@ module ActiveRecord
505
711
  # allocated but not initialized.
506
712
  inspection = if defined?(@attributes) && @attributes
507
713
  self.class.attribute_names.collect do |name|
508
- if has_attribute?(name)
509
- attr = _read_attribute(name)
510
- value = if attr.nil?
511
- attr.inspect
512
- else
513
- attr = format_for_inspect(attr)
514
- inspection_filter.filter_param(name, attr)
515
- end
516
- "#{name}: #{value}"
714
+ if _has_attribute?(name)
715
+ "#{name}: #{attribute_for_inspect(name)}"
517
716
  end
518
717
  end.compact.join(", ")
519
718
  else
@@ -529,7 +728,7 @@ module ActiveRecord
529
728
  return super if custom_inspect_method_defined?
530
729
  pp.object_address_group(self) do
531
730
  if defined?(@attributes) && @attributes
532
- attr_names = self.class.attribute_names.select { |name| has_attribute?(name) }
731
+ attr_names = self.class.attribute_names.select { |name| _has_attribute?(name) }
533
732
  pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
534
733
  pp.breakable " "
535
734
  pp.group(1) do
@@ -550,11 +749,15 @@ module ActiveRecord
550
749
 
551
750
  # Returns a hash of the given methods with their names as keys and returned values as values.
552
751
  def slice(*methods)
553
- Hash[methods.flatten.map! { |method| [method, public_send(method)] }].with_indifferent_access
752
+ methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
554
753
  end
555
754
 
556
- private
755
+ # Returns an array of the values returned by the given methods.
756
+ def values_at(*methods)
757
+ methods.flatten.map! { |method| public_send(method) }
758
+ end
557
759
 
760
+ private
558
761
  # +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
559
762
  # the array, and then rescues from the possible +NoMethodError+. If those elements are
560
763
  # +ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have,
@@ -570,11 +773,12 @@ module ActiveRecord
570
773
  def init_internals
571
774
  @primary_key = self.class.primary_key
572
775
  @readonly = false
776
+ @previously_new_record = false
573
777
  @destroyed = false
574
778
  @marked_for_destruction = false
575
779
  @destroyed_by_association = nil
576
780
  @_start_transaction_state = nil
577
- @transaction_state = nil
781
+ @strict_loading = self.class.strict_loading_by_default
578
782
 
579
783
  self.class.define_attribute_methods
580
784
  end
@@ -594,10 +798,7 @@ module ActiveRecord
594
798
  private_constant :InspectionMask
595
799
 
596
800
  def inspection_filter
597
- @inspection_filter ||= begin
598
- mask = InspectionMask.new(ActiveSupport::ParameterFilter::FILTERED)
599
- ActiveSupport::ParameterFilter.new(self.class.filter_attributes, mask: mask)
600
- end
801
+ self.class.inspection_filter
601
802
  end
602
803
  end
603
804
  end
@@ -51,7 +51,10 @@ module ActiveRecord
51
51
 
52
52
  if touch
53
53
  names = touch if touch != true
54
- updates.merge!(touch_attributes_with_time(*names))
54
+ names = Array.wrap(names)
55
+ options = names.extract_options!
56
+ touch_updates = touch_attributes_with_time(*names, **options)
57
+ updates.merge!(touch_updates)
55
58
  end
56
59
 
57
60
  unscoped.where(primary_key => object.id).update_all(updates)
@@ -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