activerecord 6.1.7.7 → 7.0.0.alpha1

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 (220) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +726 -1389
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +0 -10
  7. data/lib/active_record/associations/association.rb +31 -9
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +8 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  13. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  14. data/lib/active_record/associations/builder/has_many.rb +3 -2
  15. data/lib/active_record/associations/builder/has_one.rb +2 -1
  16. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  17. data/lib/active_record/associations/collection_association.rb +14 -23
  18. data/lib/active_record/associations/collection_proxy.rb +8 -3
  19. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  20. data/lib/active_record/associations/has_many_association.rb +1 -1
  21. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  22. data/lib/active_record/associations/has_one_association.rb +10 -7
  23. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  24. data/lib/active_record/associations/preloader/association.rb +161 -47
  25. data/lib/active_record/associations/preloader/batch.rb +51 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +37 -11
  28. data/lib/active_record/associations/preloader.rb +46 -110
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +1 -1
  31. data/lib/active_record/associations.rb +76 -81
  32. data/lib/active_record/asynchronous_queries_tracker.rb +57 -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 +41 -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 +7 -5
  39. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  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 +6 -9
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +3 -18
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/coders/yaml_column.rb +2 -14
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -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 +31 -558
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +12 -14
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +3 -3
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +112 -66
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
  61. data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -23
  62. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
  63. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
  64. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  65. data/lib/active_record/connection_adapters/pool_config.rb +1 -3
  66. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -14
  67. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  70. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  71. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  74. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  75. data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -32
  76. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
  78. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
  79. data/lib/active_record/connection_adapters/postgresql_adapter.rb +159 -102
  80. data/lib/active_record/connection_adapters/schema_cache.rb +36 -37
  81. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -19
  82. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  83. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  84. data/lib/active_record/connection_adapters.rb +6 -5
  85. data/lib/active_record/connection_handling.rb +20 -38
  86. data/lib/active_record/core.rb +111 -125
  87. data/lib/active_record/database_configurations/connection_url_resolver.rb +0 -1
  88. data/lib/active_record/database_configurations/database_config.rb +12 -0
  89. data/lib/active_record/database_configurations/hash_config.rb +27 -1
  90. data/lib/active_record/database_configurations/url_config.rb +2 -2
  91. data/lib/active_record/database_configurations.rb +17 -9
  92. data/lib/active_record/delegated_type.rb +33 -11
  93. data/lib/active_record/destroy_association_async_job.rb +1 -1
  94. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  95. data/lib/active_record/dynamic_matchers.rb +1 -1
  96. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  97. data/lib/active_record/encryption/cipher.rb +53 -0
  98. data/lib/active_record/encryption/config.rb +44 -0
  99. data/lib/active_record/encryption/configurable.rb +61 -0
  100. data/lib/active_record/encryption/context.rb +35 -0
  101. data/lib/active_record/encryption/contexts.rb +72 -0
  102. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  103. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  104. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  105. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  106. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  107. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  108. data/lib/active_record/encryption/encryptor.rb +155 -0
  109. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  110. data/lib/active_record/encryption/errors.rb +15 -0
  111. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  112. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
  113. data/lib/active_record/encryption/key.rb +28 -0
  114. data/lib/active_record/encryption/key_generator.rb +42 -0
  115. data/lib/active_record/encryption/key_provider.rb +46 -0
  116. data/lib/active_record/encryption/message.rb +33 -0
  117. data/lib/active_record/encryption/message_serializer.rb +80 -0
  118. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  119. data/lib/active_record/encryption/properties.rb +76 -0
  120. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  121. data/lib/active_record/encryption/scheme.rb +99 -0
  122. data/lib/active_record/encryption.rb +55 -0
  123. data/lib/active_record/enum.rb +41 -41
  124. data/lib/active_record/errors.rb +66 -3
  125. data/lib/active_record/fixture_set/file.rb +15 -1
  126. data/lib/active_record/fixture_set/table_row.rb +40 -5
  127. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  128. data/lib/active_record/fixtures.rb +16 -11
  129. data/lib/active_record/future_result.rb +139 -0
  130. data/lib/active_record/gem_version.rb +4 -4
  131. data/lib/active_record/inheritance.rb +55 -17
  132. data/lib/active_record/insert_all.rb +34 -5
  133. data/lib/active_record/integration.rb +1 -1
  134. data/lib/active_record/internal_metadata.rb +1 -5
  135. data/lib/active_record/locking/optimistic.rb +10 -9
  136. data/lib/active_record/log_subscriber.rb +6 -2
  137. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  138. data/lib/active_record/middleware/database_selector.rb +8 -3
  139. data/lib/active_record/migration/command_recorder.rb +4 -4
  140. data/lib/active_record/migration/compatibility.rb +89 -10
  141. data/lib/active_record/migration/join_table.rb +1 -1
  142. data/lib/active_record/migration.rb +109 -79
  143. data/lib/active_record/model_schema.rb +45 -31
  144. data/lib/active_record/nested_attributes.rb +3 -3
  145. data/lib/active_record/no_touching.rb +2 -2
  146. data/lib/active_record/null_relation.rb +2 -6
  147. data/lib/active_record/persistence.rb +134 -45
  148. data/lib/active_record/query_cache.rb +2 -2
  149. data/lib/active_record/query_logs.rb +203 -0
  150. data/lib/active_record/querying.rb +15 -5
  151. data/lib/active_record/railtie.rb +117 -17
  152. data/lib/active_record/railties/controller_runtime.rb +1 -1
  153. data/lib/active_record/railties/databases.rake +72 -48
  154. data/lib/active_record/readonly_attributes.rb +11 -0
  155. data/lib/active_record/reflection.rb +45 -44
  156. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  157. data/lib/active_record/relation/batches.rb +3 -3
  158. data/lib/active_record/relation/calculations.rb +39 -26
  159. data/lib/active_record/relation/delegation.rb +6 -6
  160. data/lib/active_record/relation/finder_methods.rb +31 -22
  161. data/lib/active_record/relation/merger.rb +20 -13
  162. data/lib/active_record/relation/predicate_builder.rb +1 -6
  163. data/lib/active_record/relation/query_attribute.rb +5 -11
  164. data/lib/active_record/relation/query_methods.rb +230 -49
  165. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  166. data/lib/active_record/relation/spawn_methods.rb +2 -2
  167. data/lib/active_record/relation/where_clause.rb +8 -4
  168. data/lib/active_record/relation.rb +166 -77
  169. data/lib/active_record/result.rb +17 -2
  170. data/lib/active_record/runtime_registry.rb +2 -4
  171. data/lib/active_record/sanitization.rb +11 -7
  172. data/lib/active_record/schema_dumper.rb +3 -3
  173. data/lib/active_record/schema_migration.rb +0 -4
  174. data/lib/active_record/scoping/default.rb +61 -12
  175. data/lib/active_record/scoping/named.rb +3 -11
  176. data/lib/active_record/scoping.rb +40 -22
  177. data/lib/active_record/serialization.rb +1 -1
  178. data/lib/active_record/signed_id.rb +1 -1
  179. data/lib/active_record/store.rb +1 -6
  180. data/lib/active_record/tasks/database_tasks.rb +106 -22
  181. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  182. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
  183. data/lib/active_record/test_databases.rb +1 -1
  184. data/lib/active_record/test_fixtures.rb +9 -13
  185. data/lib/active_record/timestamp.rb +3 -4
  186. data/lib/active_record/transactions.rb +9 -14
  187. data/lib/active_record/translation.rb +2 -2
  188. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  189. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  190. data/lib/active_record/type/internal/timezone.rb +2 -2
  191. data/lib/active_record/type/serialized.rb +1 -1
  192. data/lib/active_record/type/type_map.rb +17 -20
  193. data/lib/active_record/type.rb +1 -2
  194. data/lib/active_record/validations/associated.rb +1 -1
  195. data/lib/active_record.rb +170 -2
  196. data/lib/arel/attributes/attribute.rb +0 -8
  197. data/lib/arel/crud.rb +18 -22
  198. data/lib/arel/delete_manager.rb +2 -4
  199. data/lib/arel/insert_manager.rb +2 -3
  200. data/lib/arel/nodes/casted.rb +1 -1
  201. data/lib/arel/nodes/delete_statement.rb +8 -13
  202. data/lib/arel/nodes/insert_statement.rb +2 -2
  203. data/lib/arel/nodes/select_core.rb +2 -2
  204. data/lib/arel/nodes/select_statement.rb +2 -2
  205. data/lib/arel/nodes/update_statement.rb +3 -2
  206. data/lib/arel/predications.rb +1 -1
  207. data/lib/arel/select_manager.rb +10 -4
  208. data/lib/arel/table.rb +0 -1
  209. data/lib/arel/tree_manager.rb +0 -12
  210. data/lib/arel/update_manager.rb +2 -4
  211. data/lib/arel/visitors/dot.rb +80 -90
  212. data/lib/arel/visitors/mysql.rb +6 -1
  213. data/lib/arel/visitors/postgresql.rb +0 -10
  214. data/lib/arel/visitors/to_sql.rb +43 -2
  215. data/lib/arel.rb +1 -1
  216. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  217. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  218. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  219. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  220. metadata +55 -17
@@ -2,6 +2,15 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Scoping
5
+ class DefaultScope # :nodoc:
6
+ attr_reader :scope, :all_queries
7
+
8
+ def initialize(scope, all_queries = nil)
9
+ @scope = scope
10
+ @all_queries = all_queries
11
+ end
12
+ end
13
+
5
14
  module Default
6
15
  extend ActiveSupport::Concern
7
16
 
@@ -30,8 +39,8 @@ module ActiveRecord
30
39
  # Post.unscoped {
31
40
  # Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
32
41
  # }
33
- def unscoped
34
- block_given? ? relation.scoping { yield } : relation
42
+ def unscoped(&block)
43
+ block_given? ? relation.scoping(&block) : relation
35
44
  end
36
45
 
37
46
  # Are there attributes associated with this scope?
@@ -39,10 +48,21 @@ module ActiveRecord
39
48
  super || default_scopes.any? || respond_to?(:default_scope)
40
49
  end
41
50
 
42
- def before_remove_const #:nodoc:
51
+ def before_remove_const # :nodoc:
43
52
  self.current_scope = nil
44
53
  end
45
54
 
55
+ # Checks if the model has any default scopes. If all_queries
56
+ # is set to true, the method will check if there are any
57
+ # default_scopes for the model where +all_queries+ is true.
58
+ def default_scopes?(all_queries: false)
59
+ if all_queries
60
+ self.default_scopes.any?(&:all_queries)
61
+ else
62
+ self.default_scopes.any?
63
+ end
64
+ end
65
+
46
66
  private
47
67
  # Use this macro in your model to set a default scope for all operations on
48
68
  # the model.
@@ -54,11 +74,26 @@ module ActiveRecord
54
74
  # Article.all # => SELECT * FROM articles WHERE published = true
55
75
  #
56
76
  # The #default_scope is also applied while creating/building a record.
57
- # It is not applied while updating a record.
77
+ # It is not applied while updating or deleting a record.
58
78
  #
59
79
  # Article.new.published # => true
60
80
  # Article.create.published # => true
61
81
  #
82
+ # To apply a #default_scope when updating or deleting a record, add
83
+ # <tt>all_queries: true</tt>:
84
+ #
85
+ # class Article < ActiveRecord::Base
86
+ # default_scope { where(blog_id: 1) }, all_queries: true
87
+ # end
88
+ #
89
+ # Applying a default scope to all queries will ensure that records
90
+ # are always queried by the additional conditions. Note that only
91
+ # where clauses apply, as it does not make sense to add order to
92
+ # queries that return a single object by primary key.
93
+ #
94
+ # Article.find(1).destroy
95
+ # => DELETE ... FROM `articles` where ID = 1 AND blog_id = 1;
96
+ #
62
97
  # (You can also pass any object which responds to +call+ to the
63
98
  # +default_scope+ macro, and it will be called when building the
64
99
  # default scope.)
@@ -85,7 +120,7 @@ module ActiveRecord
85
120
  # # Should return a scope, you can call 'super' here etc.
86
121
  # end
87
122
  # end
88
- def default_scope(scope = nil, &block) # :doc:
123
+ def default_scope(scope = nil, all_queries: nil, &block) # :doc:
89
124
  scope = block if block_given?
90
125
 
91
126
  if scope.is_a?(Relation) || !scope.respond_to?(:call)
@@ -96,10 +131,12 @@ module ActiveRecord
96
131
  "self.default_scope.)"
97
132
  end
98
133
 
99
- self.default_scopes += [scope]
134
+ default_scope = DefaultScope.new(scope, all_queries)
135
+
136
+ self.default_scopes += [default_scope]
100
137
  end
101
138
 
102
- def build_default_scope(relation = relation())
139
+ def build_default_scope(relation = relation(), all_queries: nil)
103
140
  return if abstract_class?
104
141
 
105
142
  if default_scope_override.nil?
@@ -113,20 +150,32 @@ module ActiveRecord
113
150
  end
114
151
  elsif default_scopes.any?
115
152
  evaluate_default_scope do
116
- default_scopes.inject(relation) do |default_scope, scope|
117
- scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
118
- default_scope.instance_exec(&scope) || default_scope
153
+ default_scopes.inject(relation) do |default_scope, scope_obj|
154
+ if execute_scope?(all_queries, scope_obj)
155
+ scope = scope_obj.scope.respond_to?(:to_proc) ? scope_obj.scope : scope_obj.scope.method(:call)
156
+
157
+ default_scope.instance_exec(&scope) || default_scope
158
+ end
119
159
  end
120
160
  end
121
161
  end
122
162
  end
123
163
 
164
+ # If all_queries is nil, only execute on select and insert queries.
165
+ #
166
+ # If all_queries is true, check if the default_scope object has
167
+ # all_queries set, then execute on all queries; select, insert, update
168
+ # and delete.
169
+ def execute_scope?(all_queries, default_scope_obj)
170
+ all_queries.nil? || all_queries && default_scope_obj.all_queries
171
+ end
172
+
124
173
  def ignore_default_scope?
125
- ScopeRegistry.value_for(:ignore_default_scope, base_class)
174
+ ScopeRegistry.ignore_default_scope(base_class)
126
175
  end
127
176
 
128
177
  def ignore_default_scope=(ignore)
129
- ScopeRegistry.set_value_for(:ignore_default_scope, base_class, ignore)
178
+ ScopeRegistry.set_ignore_default_scope(base_class, ignore)
130
179
  end
131
180
 
132
181
  # The ignore_default_scope flag is used to prevent an infinite recursion
@@ -42,8 +42,8 @@ module ActiveRecord
42
42
  end
43
43
 
44
44
  # Returns a scope for the model with default scopes.
45
- def default_scoped(scope = relation)
46
- build_default_scope(scope) || scope
45
+ def default_scoped(scope = relation, all_queries: nil)
46
+ build_default_scope(scope, all_queries: all_queries) || scope
47
47
  end
48
48
 
49
49
  def default_extensions # :nodoc:
@@ -168,7 +168,6 @@ module ActiveRecord
168
168
  "an instance method with the same name."
169
169
  end
170
170
 
171
- valid_scope_name?(name)
172
171
  extension = Module.new(&block) if block
173
172
 
174
173
  if body.respond_to?(:to_proc)
@@ -184,7 +183,7 @@ module ActiveRecord
184
183
  scope
185
184
  end
186
185
  end
187
- singleton_class.send(:ruby2_keywords, name) if respond_to?(:ruby2_keywords, true)
186
+ singleton_class.send(:ruby2_keywords, name)
188
187
 
189
188
  generate_relation_method(name)
190
189
  end
@@ -193,13 +192,6 @@ module ActiveRecord
193
192
  def singleton_method_added(name)
194
193
  generate_relation_method(name) if Kernel.respond_to?(name) && !ActiveRecord::Relation.method_defined?(name)
195
194
  end
196
-
197
- def valid_scope_name?(name)
198
- if respond_to?(name, true) && logger
199
- logger.warn "Creating scope :#{name}. " \
200
- "Overwriting existing method #{self.name}.#{name}."
201
- end
202
- end
203
195
  end
204
196
  end
205
197
  end
@@ -24,11 +24,23 @@ module ActiveRecord
24
24
  end
25
25
 
26
26
  def current_scope(skip_inherited_scope = false)
27
- ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
27
+ ScopeRegistry.current_scope(self, skip_inherited_scope)
28
28
  end
29
29
 
30
30
  def current_scope=(scope)
31
- ScopeRegistry.set_value_for(:current_scope, self, scope)
31
+ ScopeRegistry.set_current_scope(self, scope)
32
+ end
33
+
34
+ def global_current_scope(skip_inherited_scope = false)
35
+ ScopeRegistry.global_current_scope(self, skip_inherited_scope)
36
+ end
37
+
38
+ def global_current_scope=(scope)
39
+ ScopeRegistry.set_global_current_scope(self, scope)
40
+ end
41
+
42
+ def scope_registry
43
+ ScopeRegistry.instance
32
44
  end
33
45
  end
34
46
 
@@ -69,37 +81,43 @@ module ActiveRecord
69
81
  class ScopeRegistry # :nodoc:
70
82
  extend ActiveSupport::PerThreadRegistry
71
83
 
72
- VALID_SCOPE_TYPES = [:current_scope, :ignore_default_scope]
84
+ VALID_SCOPE_TYPES = [:current_scope, :ignore_default_scope, :global_current_scope]
73
85
 
74
86
  def initialize
75
- @registry = Hash.new { |hash, key| hash[key] = {} }
87
+ @current_scope = {}
88
+ @ignore_default_scope = {}
89
+ @global_current_scope = {}
76
90
  end
77
91
 
78
- # Obtains the value for a given +scope_type+ and +model+.
79
- def value_for(scope_type, model, skip_inherited_scope = false)
80
- raise_invalid_scope_type!(scope_type)
81
- return @registry[scope_type][model.name] if skip_inherited_scope
82
- klass = model
83
- base = model.base_class
84
- while klass <= base
85
- value = @registry[scope_type][klass.name]
86
- return value if value
87
- klass = klass.superclass
92
+ VALID_SCOPE_TYPES.each do |type|
93
+ class_eval <<-eorb, __FILE__, __LINE__
94
+ def #{type}(model, skip_inherited_scope = false)
95
+ value_for(@#{type}, model, skip_inherited_scope)
88
96
  end
89
- end
90
97
 
91
- # Sets the +value+ for a given +scope_type+ and +model+.
92
- def set_value_for(scope_type, model, value)
93
- raise_invalid_scope_type!(scope_type)
94
- @registry[scope_type][model.name] = value
98
+ def set_#{type}(model, value)
99
+ set_value_for(@#{type}, model, value)
100
+ end
101
+ eorb
95
102
  end
96
103
 
97
104
  private
98
- def raise_invalid_scope_type!(scope_type)
99
- if !VALID_SCOPE_TYPES.include?(scope_type)
100
- raise ArgumentError, "Invalid scope type '#{scope_type}' sent to the registry. Scope types must be included in VALID_SCOPE_TYPES"
105
+ # Obtains the value for a given +scope_type+ and +model+.
106
+ def value_for(scope_type, model, skip_inherited_scope = false)
107
+ return scope_type[model.name] if skip_inherited_scope
108
+ klass = model
109
+ base = model.base_class
110
+ while klass <= base
111
+ value = scope_type[klass.name]
112
+ return value if value
113
+ klass = klass.superclass
101
114
  end
102
115
  end
116
+
117
+ # Sets the +value+ for a given +scope_type+ and +model+.
118
+ def set_value_for(scope_type, model, value)
119
+ scope_type[model.name] = value
120
+ end
103
121
  end
104
122
  end
105
123
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module ActiveRecord #:nodoc:
3
+ module ActiveRecord # :nodoc:
4
4
  # = Active Record \Serialization
5
5
  module Serialization
6
6
  extend ActiveSupport::Concern
@@ -10,7 +10,7 @@ module ActiveRecord
10
10
  # :singleton-method:
11
11
  # Set the secret used for the signed id verifier instance when using Active Record outside of Rails.
12
12
  # Within Rails, this is automatically set using the Rails application key generator.
13
- mattr_accessor :signed_id_verifier_secret, instance_writer: false
13
+ class_attribute :signed_id_verifier_secret, instance_writer: false
14
14
  end
15
15
 
16
16
  module ClassMethods
@@ -268,7 +268,7 @@ module ActiveRecord
268
268
  end
269
269
 
270
270
  def dump(obj)
271
- @coder.dump as_regular_hash(obj)
271
+ @coder.dump self.class.as_indifferent_hash(obj)
272
272
  end
273
273
 
274
274
  def load(yaml)
@@ -285,11 +285,6 @@ module ActiveRecord
285
285
  ActiveSupport::HashWithIndifferentAccess.new
286
286
  end
287
287
  end
288
-
289
- private
290
- def as_regular_hash(obj)
291
- obj.respond_to?(:to_hash) ? obj.to_hash : {}
292
- end
293
288
  end
294
289
  end
295
290
  end
@@ -39,11 +39,18 @@ module ActiveRecord
39
39
  ##
40
40
  # :singleton-method:
41
41
  # Extra flags passed to database CLI tool (mysqldump/pg_dump) when calling db:schema:dump
42
+ # It can be used as a string/array (the typical case) or a hash (when you use multiple adapters)
43
+ # Example:
44
+ # ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = {
45
+ # mysql2: ['--no-defaults', '--skip-add-drop-table'],
46
+ # postgres: '--no-tablespaces'
47
+ # }
42
48
  mattr_accessor :structure_dump_flags, instance_accessor: false
43
49
 
44
50
  ##
45
51
  # :singleton-method:
46
52
  # Extra flags passed to database CLI tool when calling db:schema:load
53
+ # It can be used as a string/array (the typical case) or a hash (when you use multiple adapters)
47
54
  mattr_accessor :structure_load_flags, instance_accessor: false
48
55
 
49
56
  extend self
@@ -123,7 +130,7 @@ module ActiveRecord
123
130
  env_name = options[:env] || env
124
131
  name = options[:spec] || "primary"
125
132
 
126
- @current_config ||= ActiveRecord::Base.configurations.configs_for(env_name: env_name, name: name)&.configuration_hash
133
+ @current_config ||= configs_for(env_name: env_name, name: name)&.configuration_hash
127
134
  end
128
135
  end
129
136
  deprecate :current_config
@@ -154,7 +161,7 @@ module ActiveRecord
154
161
  begin
155
162
  Rails.application.config.load_database_yaml
156
163
  rescue
157
- unless ActiveRecord::Base.suppress_multiple_database_warning
164
+ unless ActiveRecord.suppress_multiple_database_warning
158
165
  $stderr.puts "Rails couldn't infer whether you are using multiple databases from your database.yml and can't generate the tasks for the non-primary databases. If you'd like to use this feature, please simplify your ERB."
159
166
  end
160
167
 
@@ -171,12 +178,14 @@ module ActiveRecord
171
178
  return if database_configs.count == 1
172
179
 
173
180
  database_configs.each do |db_config|
181
+ next unless db_config.database_tasks?
182
+
174
183
  yield db_config.name
175
184
  end
176
185
  end
177
186
 
178
187
  def raise_for_multi_db(environment = env, command:)
179
- db_configs = ActiveRecord::Base.configurations.configs_for(env_name: environment)
188
+ db_configs = configs_for(env_name: environment)
180
189
 
181
190
  if db_configs.count > 1
182
191
  dbs_list = []
@@ -194,6 +203,39 @@ module ActiveRecord
194
203
  ActiveRecord::Base.establish_connection(environment.to_sym)
195
204
  end
196
205
 
206
+ def prepare_all
207
+ seed = false
208
+
209
+ configs_for(env_name: env).each do |db_config|
210
+ ActiveRecord::Base.establish_connection(db_config)
211
+
212
+ # Skipped when no database
213
+ migrate
214
+
215
+ if ActiveRecord.dump_schema_after_migration
216
+ dump_schema(db_config, ActiveRecord.schema_format)
217
+ end
218
+ rescue ActiveRecord::NoDatabaseError
219
+ config_name = db_config.name
220
+ create_current(db_config.env_name, config_name)
221
+
222
+ if File.exist?(dump_filename(config_name))
223
+ load_schema(
224
+ db_config,
225
+ ActiveRecord.schema_format,
226
+ nil
227
+ )
228
+ else
229
+ migrate
230
+ end
231
+
232
+ seed = true
233
+ end
234
+
235
+ ActiveRecord::Base.establish_connection
236
+ load_seed if seed
237
+ end
238
+
197
239
  def drop(configuration, *arguments)
198
240
  db_config = resolve_configuration(configuration)
199
241
  database_adapter_for(db_config, *arguments).drop
@@ -223,19 +265,21 @@ module ActiveRecord
223
265
  private :truncate_tables
224
266
 
225
267
  def truncate_all(environment = env)
226
- ActiveRecord::Base.configurations.configs_for(env_name: environment).each do |db_config|
268
+ configs_for(env_name: environment).each do |db_config|
227
269
  truncate_tables(db_config)
228
270
  end
229
271
  end
230
272
 
231
- def migrate
273
+ def migrate(version = nil)
232
274
  check_target_version
233
275
 
234
276
  scope = ENV["SCOPE"]
235
277
  verbose_was, Migration.verbose = Migration.verbose, verbose?
236
278
 
237
- Base.connection.migration_context.migrate(target_version) do |migration|
279
+ Base.connection.migration_context.migrate(target_version || version) do |migration|
238
280
  scope.blank? || scope == migration.scope
281
+ end.tap do |migrations_ran|
282
+ Migration.write("No migrations ran. (using #{scope} scope)") if scope.present? && migrations_ran.empty?
239
283
  end
240
284
 
241
285
  ActiveRecord::Base.clear_cache!
@@ -243,6 +287,23 @@ module ActiveRecord
243
287
  Migration.verbose = verbose_was
244
288
  end
245
289
 
290
+ def db_configs_with_versions(db_configs) # :nodoc:
291
+ db_configs_with_versions = Hash.new { |h, k| h[k] = [] }
292
+
293
+ db_configs.each do |db_config|
294
+ ActiveRecord::Base.establish_connection(db_config)
295
+ versions_to_run = ActiveRecord::Base.connection.migration_context.pending_migration_versions
296
+ target_version = ActiveRecord::Tasks::DatabaseTasks.target_version
297
+
298
+ versions_to_run.each do |version|
299
+ next if target_version && target_version != version
300
+ db_configs_with_versions[version] << db_config
301
+ end
302
+ end
303
+
304
+ db_configs_with_versions
305
+ end
306
+
246
307
  def migrate_status
247
308
  unless ActiveRecord::Base.connection.schema_migration.table_exists?
248
309
  Kernel.abort "Schema migrations table does not exist yet."
@@ -269,7 +330,7 @@ module ActiveRecord
269
330
  end
270
331
 
271
332
  def charset_current(env_name = env, db_name = name)
272
- db_config = ActiveRecord::Base.configurations.configs_for(env_name: env_name, name: db_name)
333
+ db_config = configs_for(env_name: env_name, name: db_name)
273
334
  charset(db_config)
274
335
  end
275
336
 
@@ -279,7 +340,7 @@ module ActiveRecord
279
340
  end
280
341
 
281
342
  def collation_current(env_name = env, db_name = name)
282
- db_config = ActiveRecord::Base.configurations.configs_for(env_name: env_name, name: db_name)
343
+ db_config = configs_for(env_name: env_name, name: db_name)
283
344
  collation(db_config)
284
345
  end
285
346
 
@@ -305,16 +366,18 @@ module ActiveRecord
305
366
  def structure_dump(configuration, *arguments)
306
367
  db_config = resolve_configuration(configuration)
307
368
  filename = arguments.delete_at(0)
308
- database_adapter_for(db_config, *arguments).structure_dump(filename, structure_dump_flags)
369
+ flags = structure_dump_flags_for(db_config.adapter)
370
+ database_adapter_for(db_config, *arguments).structure_dump(filename, flags)
309
371
  end
310
372
 
311
373
  def structure_load(configuration, *arguments)
312
374
  db_config = resolve_configuration(configuration)
313
375
  filename = arguments.delete_at(0)
314
- database_adapter_for(db_config, *arguments).structure_load(filename, structure_load_flags)
376
+ flags = structure_load_flags_for(db_config.adapter)
377
+ database_adapter_for(db_config, *arguments).structure_load(filename, flags)
315
378
  end
316
379
 
317
- def load_schema(db_config, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
380
+ def load_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
318
381
  file ||= dump_filename(db_config.name, format)
319
382
 
320
383
  verbose_was, Migration.verbose = Migration.verbose, verbose? && ENV["VERBOSE"]
@@ -336,7 +399,7 @@ module ActiveRecord
336
399
  Migration.verbose = verbose_was
337
400
  end
338
401
 
339
- def schema_up_to_date?(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = nil, name = nil)
402
+ def schema_up_to_date?(configuration, format = ActiveRecord.schema_format, file = nil, environment = nil, name = nil)
340
403
  db_config = resolve_configuration(configuration)
341
404
 
342
405
  if environment || name
@@ -357,7 +420,7 @@ module ActiveRecord
357
420
  ActiveRecord::InternalMetadata[:schema_sha1] == schema_sha1(file)
358
421
  end
359
422
 
360
- def reconstruct_from_schema(db_config, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
423
+ def reconstruct_from_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
361
424
  file ||= dump_filename(db_config.name, format)
362
425
 
363
426
  check_schema_file(file)
@@ -375,7 +438,7 @@ module ActiveRecord
375
438
  load_schema(db_config, format, file)
376
439
  end
377
440
 
378
- def dump_schema(db_config, format = ActiveRecord::Base.schema_format) # :nodoc:
441
+ def dump_schema(db_config, format = ActiveRecord.schema_format) # :nodoc:
379
442
  require "active_record/schema_dumper"
380
443
  filename = dump_filename(db_config.name, format)
381
444
  connection = ActiveRecord::Base.connection
@@ -397,11 +460,12 @@ module ActiveRecord
397
460
  end
398
461
  end
399
462
 
400
- def schema_file(format = ActiveRecord::Base.schema_format)
463
+ def schema_file(format = ActiveRecord.schema_format)
401
464
  File.join(db_dir, schema_file_type(format))
402
465
  end
466
+ deprecate :schema_file
403
467
 
404
- def schema_file_type(format = ActiveRecord::Base.schema_format)
468
+ def schema_file_type(format = ActiveRecord.schema_format)
405
469
  case format
406
470
  when :ruby
407
471
  "schema.rb"
@@ -410,7 +474,7 @@ module ActiveRecord
410
474
  end
411
475
  end
412
476
 
413
- def dump_filename(db_config_name, format = ActiveRecord::Base.schema_format)
477
+ def dump_filename(db_config_name, format = ActiveRecord.schema_format)
414
478
  filename = if ActiveRecord::Base.configurations.primary?(db_config_name)
415
479
  schema_file_type(format)
416
480
  else
@@ -430,7 +494,7 @@ module ActiveRecord
430
494
  schema_cache_path || ENV["SCHEMA_CACHE"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
431
495
  end
432
496
 
433
- def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
497
+ def load_schema_current(format = ActiveRecord.schema_format, file = nil, environment = env)
434
498
  each_current_configuration(environment) do |db_config|
435
499
  load_schema(db_config, format, file)
436
500
  end
@@ -468,6 +532,10 @@ module ActiveRecord
468
532
  end
469
533
 
470
534
  private
535
+ def configs_for(**options)
536
+ Base.configurations.configs_for(**options)
537
+ end
538
+
471
539
  def resolve_configuration(configuration)
472
540
  Base.configurations.resolve(configuration)
473
541
  end
@@ -488,7 +556,7 @@ module ActiveRecord
488
556
  end
489
557
 
490
558
  def class_for_adapter(adapter)
491
- _key, task = @tasks.each_pair.detect { |pattern, _task| adapter[pattern] }
559
+ _key, task = @tasks.reverse_each.detect { |pattern, _task| adapter[pattern] }
492
560
  unless task
493
561
  raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter"
494
562
  end
@@ -500,7 +568,7 @@ module ActiveRecord
500
568
  environments << "test" if environment == "development" && !ENV["SKIP_TEST_DATABASE"] && !ENV["DATABASE_URL"]
501
569
 
502
570
  environments.each do |env|
503
- ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
571
+ configs_for(env_name: env).each do |db_config|
504
572
  next if name && name != db_config.name
505
573
 
506
574
  yield db_config
@@ -509,7 +577,7 @@ module ActiveRecord
509
577
  end
510
578
 
511
579
  def each_local_configuration
512
- ActiveRecord::Base.configurations.configs_for.each do |db_config|
580
+ configs_for.each do |db_config|
513
581
  next unless db_config.database
514
582
 
515
583
  if local_database?(db_config)
@@ -526,7 +594,23 @@ module ActiveRecord
526
594
  end
527
595
 
528
596
  def schema_sha1(file)
529
- Digest::SHA1.hexdigest(File.read(file))
597
+ OpenSSL::Digest::SHA1.hexdigest(File.read(file))
598
+ end
599
+
600
+ def structure_dump_flags_for(adapter)
601
+ if structure_dump_flags.is_a?(Hash)
602
+ structure_dump_flags[adapter.to_sym]
603
+ else
604
+ structure_dump_flags
605
+ end
606
+ end
607
+
608
+ def structure_load_flags_for(adapter)
609
+ if structure_load_flags.is_a?(Hash)
610
+ structure_load_flags[adapter.to_sym]
611
+ else
612
+ structure_load_flags
613
+ end
530
614
  end
531
615
  end
532
616
  end
@@ -94,7 +94,7 @@ module ActiveRecord
94
94
  sslcapath: "--ssl-capath",
95
95
  sslcipher: "--ssl-cipher",
96
96
  sslkey: "--ssl-key"
97
- }.map { |opt, arg| "#{arg}=#{configuration_hash[opt]}" if configuration_hash[opt] }.compact
97
+ }.filter_map { |opt, arg| "#{arg}=#{configuration_hash[opt]}" if configuration_hash[opt] }
98
98
 
99
99
  args
100
100
  end
@@ -47,16 +47,14 @@ module ActiveRecord
47
47
  end
48
48
 
49
49
  def structure_dump(filename, extra_flags)
50
- set_psql_env
51
-
52
50
  search_path = \
53
- case ActiveRecord::Base.dump_schemas
51
+ case ActiveRecord.dump_schemas
54
52
  when :schema_search_path
55
53
  configuration_hash[:schema_search_path]
56
54
  when :all
57
55
  nil
58
56
  when String
59
- ActiveRecord::Base.dump_schemas
57
+ ActiveRecord.dump_schemas
60
58
  end
61
59
 
62
60
  args = ["--schema-only", "--no-privileges", "--no-owner", "--file", filename]
@@ -79,7 +77,6 @@ module ActiveRecord
79
77
  end
80
78
 
81
79
  def structure_load(filename, extra_flags)
82
- set_psql_env
83
80
  args = ["--set", ON_ERROR_STOP_1, "--quiet", "--no-psqlrc", "--file", filename]
84
81
  args.concat(Array(extra_flags)) if extra_flags
85
82
  args << db_config.database
@@ -100,15 +97,21 @@ module ActiveRecord
100
97
  )
101
98
  end
102
99
 
103
- def set_psql_env
104
- ENV["PGHOST"] = db_config.host if db_config.host
105
- ENV["PGPORT"] = configuration_hash[:port].to_s if configuration_hash[:port]
106
- ENV["PGPASSWORD"] = configuration_hash[:password].to_s if configuration_hash[:password]
107
- ENV["PGUSER"] = configuration_hash[:username].to_s if configuration_hash[:username]
100
+ def psql_env
101
+ {}.tap do |env|
102
+ env["PGHOST"] = db_config.host if db_config.host
103
+ env["PGPORT"] = configuration_hash[:port].to_s if configuration_hash[:port]
104
+ env["PGPASSWORD"] = configuration_hash[:password].to_s if configuration_hash[:password]
105
+ env["PGUSER"] = configuration_hash[:username].to_s if configuration_hash[:username]
106
+ env["PGSSLMODE"] = configuration_hash[:sslmode].to_s if configuration_hash[:sslmode]
107
+ env["PGSSLCERT"] = configuration_hash[:sslcert].to_s if configuration_hash[:sslcert]
108
+ env["PGSSLKEY"] = configuration_hash[:sslkey].to_s if configuration_hash[:sslkey]
109
+ env["PGSSLROOTCERT"] = configuration_hash[:sslrootcert].to_s if configuration_hash[:sslrootcert]
110
+ end
108
111
  end
109
112
 
110
113
  def run_cmd(cmd, args, action)
111
- fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
114
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(psql_env, cmd, *args)
112
115
  end
113
116
 
114
117
  def run_cmd_error(cmd, args, action)