activerecord 6.1.3.2 → 7.0.0.alpha2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (229) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +734 -1058
  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 +35 -7
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +16 -6
  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 +24 -25
  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 -49
  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 +11 -1
  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 +14 -7
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -18
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -9
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +115 -69
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
  61. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +6 -2
  62. data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -21
  63. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
  64. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -0
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  66. data/lib/active_record/connection_adapters/pool_config.rb +1 -3
  67. data/lib/active_record/connection_adapters/pool_manager.rb +5 -1
  68. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
  69. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  72. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  73. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  76. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  77. data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -6
  78. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  79. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
  80. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
  81. data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
  82. data/lib/active_record/connection_adapters/schema_cache.rb +35 -4
  83. data/lib/active_record/connection_adapters/sql_type_metadata.rb +0 -2
  84. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -17
  85. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  86. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  87. data/lib/active_record/connection_adapters.rb +8 -5
  88. data/lib/active_record/connection_handling.rb +20 -38
  89. data/lib/active_record/core.rb +129 -117
  90. data/lib/active_record/database_configurations/database_config.rb +12 -0
  91. data/lib/active_record/database_configurations/hash_config.rb +27 -1
  92. data/lib/active_record/database_configurations/url_config.rb +2 -2
  93. data/lib/active_record/database_configurations.rb +18 -9
  94. data/lib/active_record/delegated_type.rb +33 -11
  95. data/lib/active_record/destroy_association_async_job.rb +1 -1
  96. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  97. data/lib/active_record/dynamic_matchers.rb +1 -1
  98. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  99. data/lib/active_record/encryption/cipher.rb +53 -0
  100. data/lib/active_record/encryption/config.rb +44 -0
  101. data/lib/active_record/encryption/configurable.rb +61 -0
  102. data/lib/active_record/encryption/context.rb +35 -0
  103. data/lib/active_record/encryption/contexts.rb +72 -0
  104. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  105. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  106. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  107. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  108. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  109. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  110. data/lib/active_record/encryption/encryptor.rb +155 -0
  111. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  112. data/lib/active_record/encryption/errors.rb +15 -0
  113. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  114. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
  115. data/lib/active_record/encryption/key.rb +28 -0
  116. data/lib/active_record/encryption/key_generator.rb +42 -0
  117. data/lib/active_record/encryption/key_provider.rb +46 -0
  118. data/lib/active_record/encryption/message.rb +33 -0
  119. data/lib/active_record/encryption/message_serializer.rb +80 -0
  120. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  121. data/lib/active_record/encryption/properties.rb +76 -0
  122. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  123. data/lib/active_record/encryption/scheme.rb +99 -0
  124. data/lib/active_record/encryption.rb +55 -0
  125. data/lib/active_record/enum.rb +44 -46
  126. data/lib/active_record/errors.rb +66 -3
  127. data/lib/active_record/fixture_set/file.rb +15 -1
  128. data/lib/active_record/fixture_set/table_row.rb +40 -5
  129. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  130. data/lib/active_record/fixtures.rb +16 -11
  131. data/lib/active_record/future_result.rb +139 -0
  132. data/lib/active_record/gem_version.rb +4 -4
  133. data/lib/active_record/inheritance.rb +55 -17
  134. data/lib/active_record/insert_all.rb +39 -6
  135. data/lib/active_record/integration.rb +1 -1
  136. data/lib/active_record/internal_metadata.rb +3 -5
  137. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  138. data/lib/active_record/locking/optimistic.rb +10 -9
  139. data/lib/active_record/log_subscriber.rb +6 -2
  140. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  141. data/lib/active_record/middleware/database_selector.rb +8 -3
  142. data/lib/active_record/migration/command_recorder.rb +4 -4
  143. data/lib/active_record/migration/compatibility.rb +83 -1
  144. data/lib/active_record/migration/join_table.rb +1 -1
  145. data/lib/active_record/migration.rb +109 -79
  146. data/lib/active_record/model_schema.rb +46 -32
  147. data/lib/active_record/nested_attributes.rb +3 -3
  148. data/lib/active_record/no_touching.rb +2 -2
  149. data/lib/active_record/null_relation.rb +2 -6
  150. data/lib/active_record/persistence.rb +134 -45
  151. data/lib/active_record/query_cache.rb +2 -2
  152. data/lib/active_record/query_logs.rb +203 -0
  153. data/lib/active_record/querying.rb +15 -5
  154. data/lib/active_record/railtie.rb +117 -17
  155. data/lib/active_record/railties/controller_runtime.rb +1 -1
  156. data/lib/active_record/railties/databases.rake +83 -58
  157. data/lib/active_record/readonly_attributes.rb +11 -0
  158. data/lib/active_record/reflection.rb +45 -44
  159. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  160. data/lib/active_record/relation/batches.rb +3 -3
  161. data/lib/active_record/relation/calculations.rb +42 -25
  162. data/lib/active_record/relation/delegation.rb +6 -6
  163. data/lib/active_record/relation/finder_methods.rb +32 -23
  164. data/lib/active_record/relation/merger.rb +20 -13
  165. data/lib/active_record/relation/predicate_builder.rb +1 -6
  166. data/lib/active_record/relation/query_attribute.rb +5 -11
  167. data/lib/active_record/relation/query_methods.rb +233 -50
  168. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  169. data/lib/active_record/relation/spawn_methods.rb +2 -2
  170. data/lib/active_record/relation/where_clause.rb +22 -15
  171. data/lib/active_record/relation.rb +170 -87
  172. data/lib/active_record/result.rb +17 -2
  173. data/lib/active_record/runtime_registry.rb +2 -4
  174. data/lib/active_record/sanitization.rb +11 -7
  175. data/lib/active_record/schema_dumper.rb +3 -3
  176. data/lib/active_record/schema_migration.rb +0 -4
  177. data/lib/active_record/scoping/default.rb +62 -15
  178. data/lib/active_record/scoping/named.rb +3 -11
  179. data/lib/active_record/scoping.rb +40 -22
  180. data/lib/active_record/serialization.rb +1 -1
  181. data/lib/active_record/signed_id.rb +1 -1
  182. data/lib/active_record/statement_cache.rb +2 -2
  183. data/lib/active_record/tasks/database_tasks.rb +107 -23
  184. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  185. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
  186. data/lib/active_record/test_databases.rb +1 -1
  187. data/lib/active_record/test_fixtures.rb +45 -4
  188. data/lib/active_record/timestamp.rb +3 -4
  189. data/lib/active_record/transactions.rb +9 -14
  190. data/lib/active_record/translation.rb +2 -2
  191. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  192. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  193. data/lib/active_record/type/internal/timezone.rb +2 -2
  194. data/lib/active_record/type/serialized.rb +1 -1
  195. data/lib/active_record/type/type_map.rb +17 -20
  196. data/lib/active_record/type.rb +1 -2
  197. data/lib/active_record/validations/associated.rb +1 -1
  198. data/lib/active_record/validations/numericality.rb +1 -1
  199. data/lib/active_record.rb +170 -2
  200. data/lib/arel/attributes/attribute.rb +0 -8
  201. data/lib/arel/collectors/bind.rb +2 -2
  202. data/lib/arel/collectors/composite.rb +3 -3
  203. data/lib/arel/collectors/sql_string.rb +1 -1
  204. data/lib/arel/collectors/substitute_binds.rb +1 -1
  205. data/lib/arel/crud.rb +18 -22
  206. data/lib/arel/delete_manager.rb +2 -4
  207. data/lib/arel/insert_manager.rb +2 -3
  208. data/lib/arel/nodes/casted.rb +1 -1
  209. data/lib/arel/nodes/delete_statement.rb +8 -13
  210. data/lib/arel/nodes/homogeneous_in.rb +4 -0
  211. data/lib/arel/nodes/insert_statement.rb +2 -2
  212. data/lib/arel/nodes/select_core.rb +2 -2
  213. data/lib/arel/nodes/select_statement.rb +2 -2
  214. data/lib/arel/nodes/update_statement.rb +3 -2
  215. data/lib/arel/predications.rb +3 -3
  216. data/lib/arel/select_manager.rb +10 -4
  217. data/lib/arel/table.rb +0 -1
  218. data/lib/arel/tree_manager.rb +0 -12
  219. data/lib/arel/update_manager.rb +2 -4
  220. data/lib/arel/visitors/dot.rb +80 -90
  221. data/lib/arel/visitors/mysql.rb +6 -1
  222. data/lib/arel/visitors/postgresql.rb +0 -10
  223. data/lib/arel/visitors/to_sql.rb +44 -3
  224. data/lib/arel.rb +1 -1
  225. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  226. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  227. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  228. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  229. metadata +55 -16
@@ -36,6 +36,10 @@ module ActiveRecord
36
36
 
37
37
  attr_reader :columns, :rows, :column_types
38
38
 
39
+ def self.empty # :nodoc:
40
+ EMPTY
41
+ end
42
+
39
43
  def initialize(columns, rows, column_types = {})
40
44
  @columns = columns
41
45
  @rows = rows
@@ -43,6 +47,9 @@ module ActiveRecord
43
47
  @column_types = column_types
44
48
  end
45
49
 
50
+ EMPTY = new([].freeze, [].freeze, {}.freeze)
51
+ private_constant :EMPTY
52
+
46
53
  # Returns true if this result set includes the column named +name+
47
54
  def includes_column?(name)
48
55
  @columns.include? name
@@ -57,9 +64,9 @@ module ActiveRecord
57
64
  # row as parameter.
58
65
  #
59
66
  # Returns an +Enumerator+ if no block is given.
60
- def each
67
+ def each(&block)
61
68
  if block_given?
62
- hash_rows.each { |row| yield row }
69
+ hash_rows.each(&block)
63
70
  else
64
71
  hash_rows.to_enum { @rows.size }
65
72
  end
@@ -91,6 +98,14 @@ module ActiveRecord
91
98
  n ? hash_rows.last(n) : hash_rows.last
92
99
  end
93
100
 
101
+ def result # :nodoc:
102
+ self
103
+ end
104
+
105
+ def cancel # :nodoc:
106
+ self
107
+ end
108
+
94
109
  def cast_values(type_overrides = {}) # :nodoc:
95
110
  if columns.one?
96
111
  # Separated to avoid allocating an array per row
@@ -16,9 +16,7 @@ module ActiveRecord
16
16
 
17
17
  attr_accessor :sql_runtime
18
18
 
19
- [:sql_runtime].each do |val|
20
- class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
21
- class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
22
- end
19
+ def self.sql_runtime; instance.sql_runtime; end
20
+ def self.sql_runtime=(x); instance.sql_runtime = x; end
23
21
  end
24
22
  end
@@ -54,7 +54,7 @@ module ActiveRecord
54
54
  # Accepts an array, or string of SQL conditions and sanitizes
55
55
  # them into a valid SQL fragment for an ORDER clause.
56
56
  #
57
- # sanitize_sql_for_order(["field(id, ?)", [1,3,2]])
57
+ # sanitize_sql_for_order([Arel.sql("field(id, ?)"), [1,3,2]])
58
58
  # # => "field(id, 1,3,2)"
59
59
  #
60
60
  # sanitize_sql_for_order("id ASC")
@@ -137,14 +137,18 @@ module ActiveRecord
137
137
  def disallow_raw_sql!(args, permit: connection.column_name_matcher) # :nodoc:
138
138
  unexpected = nil
139
139
  args.each do |arg|
140
- next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s)
140
+ next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s.strip)
141
141
  (unexpected ||= []) << arg
142
142
  end
143
143
 
144
144
  if unexpected
145
145
  raise(ActiveRecord::UnknownAttributeReference,
146
- "Query method called with non-attribute argument(s): " +
147
- unexpected.map(&:inspect).join(", ")
146
+ "Dangerous query method (method whose arguments are used as raw " \
147
+ "SQL) called with non-attribute argument(s): " \
148
+ "#{unexpected.map(&:inspect).join(", ")}." \
149
+ "This method should not be called with user-provided values, such as request " \
150
+ "parameters or model attributes. Known-safe values can be passed " \
151
+ "by wrapping them in Arel.sql()."
148
152
  )
149
153
  end
150
154
  end
@@ -183,13 +187,13 @@ module ActiveRecord
183
187
  if value.respond_to?(:map) && !value.acts_like?(:string)
184
188
  values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
185
189
  if values.empty?
186
- c.quote(nil)
190
+ c.quote_bound_value(nil)
187
191
  else
188
- values.map! { |v| c.quote(v) }.join(",")
192
+ values.map! { |v| c.quote_bound_value(v) }.join(",")
189
193
  end
190
194
  else
191
195
  value = value.id_for_database if value.respond_to?(:id_for_database)
192
- c.quote(value)
196
+ c.quote_bound_value(value)
193
197
  end
194
198
  end
195
199
 
@@ -7,14 +7,14 @@ module ActiveRecord
7
7
  #
8
8
  # This class is used to dump the database schema for some connection to some
9
9
  # output format (i.e., ActiveRecord::Schema).
10
- class SchemaDumper #:nodoc:
10
+ class SchemaDumper # :nodoc:
11
11
  private_class_method :new
12
12
 
13
13
  ##
14
14
  # :singleton-method:
15
15
  # A list of tables which should not be dumped to the schema.
16
- # Acceptable values are strings as well as regexp if ActiveRecord::Base.schema_format == :ruby.
17
- # Only strings are accepted if ActiveRecord::Base.schema_format == :sql.
16
+ # Acceptable values are strings as well as regexp if ActiveRecord.schema_format == :ruby.
17
+ # Only strings are accepted if ActiveRecord.schema_format == :sql.
18
18
  cattr_accessor :ignore_tables, default: []
19
19
 
20
20
  ##
@@ -10,10 +10,6 @@ module ActiveRecord
10
10
  # to be executed the next time.
11
11
  class SchemaMigration < ActiveRecord::Base # :nodoc:
12
12
  class << self
13
- def _internal?
14
- true
15
- end
16
-
17
13
  def primary_key
18
14
  "version"
19
15
  end
@@ -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?
@@ -109,26 +146,36 @@ module ActiveRecord
109
146
  if default_scope_override
110
147
  # The user has defined their own default scope method, so call that
111
148
  evaluate_default_scope do
112
- if scope = default_scope
113
- relation.merge!(scope)
114
- end
149
+ relation.scoping { default_scope }
115
150
  end
116
151
  elsif default_scopes.any?
117
152
  evaluate_default_scope do
118
- default_scopes.inject(relation) do |default_scope, scope|
119
- scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
120
- 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
121
159
  end
122
160
  end
123
161
  end
124
162
  end
125
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
+
126
173
  def ignore_default_scope?
127
- ScopeRegistry.value_for(:ignore_default_scope, base_class)
174
+ ScopeRegistry.ignore_default_scope(base_class)
128
175
  end
129
176
 
130
177
  def ignore_default_scope=(ignore)
131
- ScopeRegistry.set_value_for(:ignore_default_scope, base_class, ignore)
178
+ ScopeRegistry.set_ignore_default_scope(base_class, ignore)
132
179
  end
133
180
 
134
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
@@ -80,8 +80,8 @@ module ActiveRecord
80
80
  self
81
81
  end
82
82
 
83
- def add_binds(binds)
84
- @binds.concat binds
83
+ def add_binds(binds, proc_for_binds = nil)
84
+ @binds.concat proc_for_binds ? binds.map(&proc_for_binds) : binds
85
85
  binds.size.times do |i|
86
86
  @parts << ", " unless i == 0
87
87
  @parts << Substitute.new
@@ -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,11 +399,11 @@ 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
343
- ActiveSupport::Deprecation.warn("`environment` and `name` will be removed as parameters in 6.2.0, you may now pass an ActiveRecord::DatabaseConfigurations::DatabaseConfig as `configuration` instead.")
406
+ ActiveSupport::Deprecation.warn("`environment` and `name` will be removed as parameters in 7.0.0, you may now pass an ActiveRecord::DatabaseConfigurations::DatabaseConfig as `configuration` instead.")
344
407
  end
345
408
 
346
409
  name ||= db_config.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