activerecord 6.1.7.4 → 7.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (249) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1449 -1014
  3. data/README.rdoc +3 -3
  4. data/lib/active_record/aggregations.rb +1 -1
  5. data/lib/active_record/association_relation.rb +0 -10
  6. data/lib/active_record/associations/association.rb +33 -17
  7. data/lib/active_record/associations/association_scope.rb +1 -3
  8. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  10. data/lib/active_record/associations/builder/association.rb +8 -2
  11. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  12. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  13. data/lib/active_record/associations/builder/has_many.rb +3 -2
  14. data/lib/active_record/associations/builder/has_one.rb +2 -1
  15. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  16. data/lib/active_record/associations/collection_association.rb +19 -21
  17. data/lib/active_record/associations/collection_proxy.rb +10 -5
  18. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  19. data/lib/active_record/associations/has_many_association.rb +8 -5
  20. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  21. data/lib/active_record/associations/has_one_association.rb +14 -7
  22. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  23. data/lib/active_record/associations/join_dependency.rb +23 -15
  24. data/lib/active_record/associations/preloader/association.rb +186 -52
  25. data/lib/active_record/associations/preloader/batch.rb +48 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  28. data/lib/active_record/associations/preloader.rb +39 -113
  29. data/lib/active_record/associations/singular_association.rb +15 -7
  30. data/lib/active_record/associations/through_association.rb +3 -3
  31. data/lib/active_record/associations.rb +138 -100
  32. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +49 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +8 -6
  39. data/lib/active_record/attribute_methods/serialization.rb +57 -19
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +19 -22
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +17 -28
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +14 -16
  47. data/lib/active_record/coders/yaml_column.rb +4 -8
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +42 -72
  56. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  57. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +52 -23
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +82 -25
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +153 -74
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +112 -84
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -24
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +45 -21
  66. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +4 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  68. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  70. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  71. data/lib/active_record/connection_adapters/postgresql/column.rb +19 -1
  72. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -17
  73. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  77. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  78. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  81. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  82. data/lib/active_record/connection_adapters/postgresql/quoting.rb +71 -71
  83. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
  84. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  85. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  86. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  87. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +40 -21
  88. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  89. data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -106
  90. data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
  91. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
  92. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
  93. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +17 -15
  94. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +97 -32
  95. data/lib/active_record/connection_adapters.rb +6 -5
  96. data/lib/active_record/connection_handling.rb +49 -55
  97. data/lib/active_record/core.rb +123 -148
  98. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  99. data/lib/active_record/database_configurations/database_config.rb +12 -9
  100. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  101. data/lib/active_record/database_configurations/url_config.rb +2 -2
  102. data/lib/active_record/database_configurations.rb +15 -32
  103. data/lib/active_record/delegated_type.rb +53 -12
  104. data/lib/active_record/destroy_association_async_job.rb +1 -1
  105. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  106. data/lib/active_record/dynamic_matchers.rb +1 -1
  107. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  108. data/lib/active_record/encryption/cipher.rb +53 -0
  109. data/lib/active_record/encryption/config.rb +44 -0
  110. data/lib/active_record/encryption/configurable.rb +67 -0
  111. data/lib/active_record/encryption/context.rb +35 -0
  112. data/lib/active_record/encryption/contexts.rb +72 -0
  113. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  114. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  115. data/lib/active_record/encryption/encryptable_record.rb +206 -0
  116. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  117. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  118. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  119. data/lib/active_record/encryption/encryptor.rb +155 -0
  120. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  121. data/lib/active_record/encryption/errors.rb +15 -0
  122. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  123. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  124. data/lib/active_record/encryption/key.rb +28 -0
  125. data/lib/active_record/encryption/key_generator.rb +42 -0
  126. data/lib/active_record/encryption/key_provider.rb +46 -0
  127. data/lib/active_record/encryption/message.rb +33 -0
  128. data/lib/active_record/encryption/message_serializer.rb +90 -0
  129. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  130. data/lib/active_record/encryption/properties.rb +76 -0
  131. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  132. data/lib/active_record/encryption/scheme.rb +99 -0
  133. data/lib/active_record/encryption.rb +55 -0
  134. data/lib/active_record/enum.rb +50 -43
  135. data/lib/active_record/errors.rb +67 -4
  136. data/lib/active_record/explain_registry.rb +11 -6
  137. data/lib/active_record/explain_subscriber.rb +1 -1
  138. data/lib/active_record/fixture_set/file.rb +15 -1
  139. data/lib/active_record/fixture_set/table_row.rb +41 -6
  140. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  141. data/lib/active_record/fixtures.rb +20 -23
  142. data/lib/active_record/future_result.rb +139 -0
  143. data/lib/active_record/gem_version.rb +5 -5
  144. data/lib/active_record/inheritance.rb +55 -17
  145. data/lib/active_record/insert_all.rb +80 -14
  146. data/lib/active_record/integration.rb +4 -3
  147. data/lib/active_record/internal_metadata.rb +1 -5
  148. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  149. data/lib/active_record/locking/optimistic.rb +36 -21
  150. data/lib/active_record/locking/pessimistic.rb +10 -4
  151. data/lib/active_record/log_subscriber.rb +23 -7
  152. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  153. data/lib/active_record/middleware/database_selector.rb +18 -6
  154. data/lib/active_record/middleware/shard_selector.rb +60 -0
  155. data/lib/active_record/migration/command_recorder.rb +8 -9
  156. data/lib/active_record/migration/compatibility.rb +91 -2
  157. data/lib/active_record/migration/join_table.rb +1 -1
  158. data/lib/active_record/migration.rb +115 -84
  159. data/lib/active_record/model_schema.rb +58 -59
  160. data/lib/active_record/nested_attributes.rb +13 -12
  161. data/lib/active_record/no_touching.rb +3 -3
  162. data/lib/active_record/null_relation.rb +2 -6
  163. data/lib/active_record/persistence.rb +228 -60
  164. data/lib/active_record/query_cache.rb +2 -2
  165. data/lib/active_record/query_logs.rb +149 -0
  166. data/lib/active_record/querying.rb +16 -6
  167. data/lib/active_record/railtie.rb +136 -22
  168. data/lib/active_record/railties/controller_runtime.rb +1 -1
  169. data/lib/active_record/railties/databases.rake +78 -136
  170. data/lib/active_record/readonly_attributes.rb +11 -0
  171. data/lib/active_record/reflection.rb +80 -49
  172. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  173. data/lib/active_record/relation/batches.rb +6 -6
  174. data/lib/active_record/relation/calculations.rb +92 -60
  175. data/lib/active_record/relation/delegation.rb +7 -7
  176. data/lib/active_record/relation/finder_methods.rb +31 -35
  177. data/lib/active_record/relation/merger.rb +20 -13
  178. data/lib/active_record/relation/predicate_builder/association_query_value.rb +20 -1
  179. data/lib/active_record/relation/predicate_builder.rb +2 -6
  180. data/lib/active_record/relation/query_attribute.rb +5 -11
  181. data/lib/active_record/relation/query_methods.rb +285 -68
  182. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  183. data/lib/active_record/relation/spawn_methods.rb +2 -2
  184. data/lib/active_record/relation/where_clause.rb +10 -19
  185. data/lib/active_record/relation.rb +189 -88
  186. data/lib/active_record/result.rb +23 -11
  187. data/lib/active_record/runtime_registry.rb +9 -13
  188. data/lib/active_record/sanitization.rb +17 -12
  189. data/lib/active_record/schema.rb +38 -23
  190. data/lib/active_record/schema_dumper.rb +29 -19
  191. data/lib/active_record/schema_migration.rb +4 -4
  192. data/lib/active_record/scoping/default.rb +60 -13
  193. data/lib/active_record/scoping/named.rb +3 -11
  194. data/lib/active_record/scoping.rb +64 -34
  195. data/lib/active_record/serialization.rb +6 -1
  196. data/lib/active_record/signed_id.rb +3 -3
  197. data/lib/active_record/store.rb +2 -2
  198. data/lib/active_record/suppressor.rb +11 -15
  199. data/lib/active_record/table_metadata.rb +5 -1
  200. data/lib/active_record/tasks/database_tasks.rb +127 -60
  201. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  202. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
  203. data/lib/active_record/test_databases.rb +1 -1
  204. data/lib/active_record/test_fixtures.rb +9 -6
  205. data/lib/active_record/timestamp.rb +3 -4
  206. data/lib/active_record/transactions.rb +9 -14
  207. data/lib/active_record/translation.rb +3 -3
  208. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  209. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  210. data/lib/active_record/type/internal/timezone.rb +2 -2
  211. data/lib/active_record/type/serialized.rb +5 -5
  212. data/lib/active_record/type/type_map.rb +17 -20
  213. data/lib/active_record/type.rb +1 -2
  214. data/lib/active_record/validations/associated.rb +4 -4
  215. data/lib/active_record/validations/presence.rb +2 -2
  216. data/lib/active_record/validations/uniqueness.rb +4 -4
  217. data/lib/active_record/version.rb +1 -1
  218. data/lib/active_record.rb +225 -27
  219. data/lib/arel/attributes/attribute.rb +0 -8
  220. data/lib/arel/crud.rb +28 -22
  221. data/lib/arel/delete_manager.rb +18 -4
  222. data/lib/arel/filter_predications.rb +9 -0
  223. data/lib/arel/insert_manager.rb +2 -3
  224. data/lib/arel/nodes/casted.rb +1 -1
  225. data/lib/arel/nodes/delete_statement.rb +12 -13
  226. data/lib/arel/nodes/filter.rb +10 -0
  227. data/lib/arel/nodes/function.rb +1 -0
  228. data/lib/arel/nodes/insert_statement.rb +2 -2
  229. data/lib/arel/nodes/select_core.rb +2 -2
  230. data/lib/arel/nodes/select_statement.rb +2 -2
  231. data/lib/arel/nodes/update_statement.rb +8 -3
  232. data/lib/arel/nodes.rb +1 -0
  233. data/lib/arel/predications.rb +11 -3
  234. data/lib/arel/select_manager.rb +10 -4
  235. data/lib/arel/table.rb +0 -1
  236. data/lib/arel/tree_manager.rb +0 -12
  237. data/lib/arel/update_manager.rb +18 -4
  238. data/lib/arel/visitors/dot.rb +80 -90
  239. data/lib/arel/visitors/mysql.rb +8 -2
  240. data/lib/arel/visitors/postgresql.rb +0 -10
  241. data/lib/arel/visitors/to_sql.rb +58 -2
  242. data/lib/arel.rb +2 -1
  243. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  244. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  245. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  246. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  247. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  248. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  249. metadata +58 -14
@@ -1,24 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/per_thread_registry"
4
-
5
3
  module ActiveRecord
6
4
  # This is a thread locals registry for Active Record. For example:
7
5
  #
8
- # ActiveRecord::RuntimeRegistry.connection_handler
9
- #
10
- # returns the connection handler local to the current thread.
6
+ # ActiveRecord::RuntimeRegistry.sql_runtime
11
7
  #
12
- # See the documentation of ActiveSupport::PerThreadRegistry
13
- # for further details.
14
- class RuntimeRegistry # :nodoc:
15
- extend ActiveSupport::PerThreadRegistry
8
+ # returns the connection handler local to the current unit of execution (either thread of fiber).
9
+ module RuntimeRegistry # :nodoc:
10
+ extend self
16
11
 
17
- attr_accessor :sql_runtime
12
+ def sql_runtime
13
+ ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime]
14
+ end
18
15
 
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__
16
+ def sql_runtime=(runtime)
17
+ ActiveSupport::IsolatedExecutionState[:active_record_sql_runtime] = runtime
22
18
  end
23
19
  end
24
20
  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")
@@ -92,16 +92,17 @@ module ActiveRecord
92
92
  end
93
93
 
94
94
  # Sanitizes a +string+ so that it is safe to use within an SQL
95
- # LIKE statement. This method uses +escape_character+ to escape all occurrences of "\", "_" and "%".
95
+ # LIKE statement. This method uses +escape_character+ to escape all
96
+ # occurrences of itself, "_" and "%".
96
97
  #
97
- # sanitize_sql_like("100%")
98
- # # => "100\\%"
98
+ # sanitize_sql_like("100% true!")
99
+ # # => "100\\% true!"
99
100
  #
100
101
  # sanitize_sql_like("snake_cased_string")
101
102
  # # => "snake\\_cased\\_string"
102
103
  #
103
- # sanitize_sql_like("100%", "!")
104
- # # => "100!%"
104
+ # sanitize_sql_like("100% true!", "!")
105
+ # # => "100!% true!!"
105
106
  #
106
107
  # sanitize_sql_like("snake_cased_string", "!")
107
108
  # # => "snake!_cased!_string"
@@ -137,14 +138,18 @@ module ActiveRecord
137
138
  def disallow_raw_sql!(args, permit: connection.column_name_matcher) # :nodoc:
138
139
  unexpected = nil
139
140
  args.each do |arg|
140
- next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s)
141
+ next if arg.is_a?(Symbol) || Arel.arel_node?(arg) || permit.match?(arg.to_s.strip)
141
142
  (unexpected ||= []) << arg
142
143
  end
143
144
 
144
145
  if unexpected
145
146
  raise(ActiveRecord::UnknownAttributeReference,
146
- "Query method called with non-attribute argument(s): " +
147
- unexpected.map(&:inspect).join(", ")
147
+ "Dangerous query method (method whose arguments are used as raw " \
148
+ "SQL) called with non-attribute argument(s): " \
149
+ "#{unexpected.map(&:inspect).join(", ")}." \
150
+ "This method should not be called with user-provided values, such as request " \
151
+ "parameters or model attributes. Known-safe values can be passed " \
152
+ "by wrapping them in Arel.sql()."
148
153
  )
149
154
  end
150
155
  end
@@ -183,13 +188,13 @@ module ActiveRecord
183
188
  if value.respond_to?(:map) && !value.acts_like?(:string)
184
189
  values = value.map { |v| v.respond_to?(:id_for_database) ? v.id_for_database : v }
185
190
  if values.empty?
186
- c.quote(nil)
191
+ c.quote_bound_value(nil)
187
192
  else
188
- values.map! { |v| c.quote(v) }.join(",")
193
+ values.map! { |v| c.quote_bound_value(v) }.join(",")
189
194
  end
190
195
  else
191
196
  value = value.id_for_database if value.respond_to?(:id_for_database)
192
- c.quote(value)
197
+ c.quote_bound_value(value)
193
198
  end
194
199
  end
195
200
 
@@ -10,7 +10,7 @@ module ActiveRecord
10
10
  #
11
11
  # Usage:
12
12
  #
13
- # ActiveRecord::Schema.define do
13
+ # ActiveRecord::Schema[7.0].define do
14
14
  # create_table :authors do |t|
15
15
  # t.string :name, null: false
16
16
  # end
@@ -30,32 +30,47 @@ module ActiveRecord
30
30
  # ActiveRecord::Schema is only supported by database adapters that also
31
31
  # support migrations, the two features being very similar.
32
32
  class Schema < Migration::Current
33
- # Eval the given block. All methods available to the current connection
34
- # adapter are available within the block, so you can easily use the
35
- # database definition DSL to build up your schema (
36
- # {create_table}[rdoc-ref:ConnectionAdapters::SchemaStatements#create_table],
37
- # {add_index}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_index], etc.).
38
- #
39
- # The +info+ hash is optional, and if given is used to define metadata
40
- # about the current schema (currently, only the schema's version):
41
- #
42
- # ActiveRecord::Schema.define(version: 2038_01_19_000001) do
43
- # ...
44
- # end
45
- def self.define(info = {}, &block)
46
- new.define(info, &block)
47
- end
33
+ module Definition
34
+ extend ActiveSupport::Concern
35
+
36
+ module ClassMethods
37
+ # Eval the given block. All methods available to the current connection
38
+ # adapter are available within the block, so you can easily use the
39
+ # database definition DSL to build up your schema (
40
+ # {create_table}[rdoc-ref:ConnectionAdapters::SchemaStatements#create_table],
41
+ # {add_index}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_index], etc.).
42
+ #
43
+ # The +info+ hash is optional, and if given is used to define metadata
44
+ # about the current schema (currently, only the schema's version):
45
+ #
46
+ # ActiveRecord::Schema[7.0].define(version: 2038_01_19_000001) do
47
+ # ...
48
+ # end
49
+ def define(info = {}, &block)
50
+ new.define(info, &block)
51
+ end
52
+ end
53
+
54
+ def define(info, &block) # :nodoc:
55
+ instance_eval(&block)
48
56
 
49
- def define(info, &block) # :nodoc:
50
- instance_eval(&block)
57
+ if info[:version].present?
58
+ connection.schema_migration.create_table
59
+ connection.assume_migrated_upto_version(info[:version])
60
+ end
51
61
 
52
- if info[:version].present?
53
- connection.schema_migration.create_table
54
- connection.assume_migrated_upto_version(info[:version])
62
+ ActiveRecord::InternalMetadata.create_table
63
+ ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
55
64
  end
65
+ end
66
+
67
+ include Definition
56
68
 
57
- ActiveRecord::InternalMetadata.create_table
58
- ActiveRecord::InternalMetadata[:environment] = connection.migration_context.current_environment
69
+ def self.[](version)
70
+ @class_for_version ||= {}
71
+ @class_for_version[version] ||= Class.new(Migration::Compatibility.find(version)) do
72
+ include Definition
73
+ end
59
74
  end
60
75
  end
61
76
  end
@@ -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
  ##
@@ -47,6 +47,7 @@ module ActiveRecord
47
47
  def dump(stream)
48
48
  header(stream)
49
49
  extensions(stream)
50
+ types(stream)
50
51
  tables(stream)
51
52
  trailer(stream)
52
53
  stream
@@ -73,22 +74,21 @@ module ActiveRecord
73
74
  end
74
75
 
75
76
  def header(stream)
76
- stream.puts <<HEADER
77
- # This file is auto-generated from the current state of the database. Instead
78
- # of editing this file, please use the migrations feature of Active Record to
79
- # incrementally modify your database, and then regenerate this schema definition.
80
- #
81
- # This file is the source Rails uses to define your schema when running `bin/rails
82
- # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
83
- # be faster and is potentially less error prone than running all of your
84
- # migrations from scratch. Old migrations may fail to apply correctly if those
85
- # migrations use external dependencies or application code.
86
- #
87
- # It's strongly recommended that you check this file into your version control system.
88
-
89
- ActiveRecord::Schema.define(#{define_params}) do
90
-
91
- HEADER
77
+ stream.puts <<~HEADER
78
+ # This file is auto-generated from the current state of the database. Instead
79
+ # of editing this file, please use the migrations feature of Active Record to
80
+ # incrementally modify your database, and then regenerate this schema definition.
81
+ #
82
+ # This file is the source Rails uses to define your schema when running `bin/rails
83
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
84
+ # be faster and is potentially less error prone than running all of your
85
+ # migrations from scratch. Old migrations may fail to apply correctly if those
86
+ # migrations use external dependencies or application code.
87
+ #
88
+ # It's strongly recommended that you check this file into your version control system.
89
+
90
+ ActiveRecord::Schema[#{ActiveRecord::Migration.current_version}].define(#{define_params}) do
91
+ HEADER
92
92
  end
93
93
 
94
94
  def trailer(stream)
@@ -99,6 +99,10 @@ HEADER
99
99
  def extensions(stream)
100
100
  end
101
101
 
102
+ # (enum) types are only supported by PostgreSQL
103
+ def types(stream)
104
+ end
105
+
102
106
  def tables(stream)
103
107
  sorted_tables = @connection.tables.sort
104
108
 
@@ -154,6 +158,7 @@ HEADER
154
158
  columns.each do |column|
155
159
  raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
156
160
  next if column.name == pk
161
+
157
162
  type, colspec = column_spec(column)
158
163
  if type.is_a?(Symbol)
159
164
  tbl.print " t.#{type} #{column.name.inspect}"
@@ -259,6 +264,7 @@ HEADER
259
264
 
260
265
  parts << "on_update: #{foreign_key.on_update.inspect}" if foreign_key.on_update
261
266
  parts << "on_delete: #{foreign_key.on_delete.inspect}" if foreign_key.on_delete
267
+ parts << "deferrable: #{foreign_key.deferrable.inspect}" if foreign_key.deferrable
262
268
 
263
269
  " #{parts.join(', ')}"
264
270
  end
@@ -286,6 +292,10 @@ HEADER
286
292
  end
287
293
 
288
294
  def remove_prefix_and_suffix(table)
295
+ # This method appears at the top when profiling active_record test cases run.
296
+ # Avoid costly calculation when there are no prefix and suffix.
297
+ return table if @options[:table_name_prefix].blank? && @options[:table_name_suffix].blank?
298
+
289
299
  prefix = Regexp.escape(@options[:table_name_prefix].to_s)
290
300
  suffix = Regexp.escape(@options[:table_name_suffix].to_s)
291
301
  table.sub(/\A#{prefix}(.+)#{suffix}\z/, "\\1")
@@ -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
@@ -45,6 +41,10 @@ module ActiveRecord
45
41
  def all_versions
46
42
  order(:version).pluck(:version)
47
43
  end
44
+
45
+ def table_exists?
46
+ connection.data_source_exists?(table_name)
47
+ end
48
48
  end
49
49
 
50
50
  def version
@@ -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,8 +48,15 @@ module ActiveRecord
39
48
  super || default_scopes.any? || respond_to?(:default_scope)
40
49
  end
41
50
 
42
- def before_remove_const #:nodoc:
43
- self.current_scope = nil
51
+ # Checks if the model has any default scopes. If all_queries
52
+ # is set to true, the method will check if there are any
53
+ # default_scopes for the model where +all_queries+ is true.
54
+ def default_scopes?(all_queries: false)
55
+ if all_queries
56
+ self.default_scopes.any?(&:all_queries)
57
+ else
58
+ self.default_scopes.any?
59
+ end
44
60
  end
45
61
 
46
62
  private
@@ -54,11 +70,26 @@ module ActiveRecord
54
70
  # Article.all # => SELECT * FROM articles WHERE published = true
55
71
  #
56
72
  # The #default_scope is also applied while creating/building a record.
57
- # It is not applied while updating a record.
73
+ # It is not applied while updating or deleting a record.
58
74
  #
59
75
  # Article.new.published # => true
60
76
  # Article.create.published # => true
61
77
  #
78
+ # To apply a #default_scope when updating or deleting a record, add
79
+ # <tt>all_queries: true</tt>:
80
+ #
81
+ # class Article < ActiveRecord::Base
82
+ # default_scope -> { where(blog_id: 1) }, all_queries: true
83
+ # end
84
+ #
85
+ # Applying a default scope to all queries will ensure that records
86
+ # are always queried by the additional conditions. Note that only
87
+ # where clauses apply, as it does not make sense to add order to
88
+ # queries that return a single object by primary key.
89
+ #
90
+ # Article.find(1).destroy
91
+ # => DELETE ... FROM `articles` where ID = 1 AND blog_id = 1;
92
+ #
62
93
  # (You can also pass any object which responds to +call+ to the
63
94
  # +default_scope+ macro, and it will be called when building the
64
95
  # default scope.)
@@ -85,7 +116,7 @@ module ActiveRecord
85
116
  # # Should return a scope, you can call 'super' here etc.
86
117
  # end
87
118
  # end
88
- def default_scope(scope = nil, &block) # :doc:
119
+ def default_scope(scope = nil, all_queries: nil, &block) # :doc:
89
120
  scope = block if block_given?
90
121
 
91
122
  if scope.is_a?(Relation) || !scope.respond_to?(:call)
@@ -96,10 +127,12 @@ module ActiveRecord
96
127
  "self.default_scope.)"
97
128
  end
98
129
 
99
- self.default_scopes += [scope]
130
+ default_scope = DefaultScope.new(scope, all_queries)
131
+
132
+ self.default_scopes += [default_scope]
100
133
  end
101
134
 
102
- def build_default_scope(relation = relation())
135
+ def build_default_scope(relation = relation(), all_queries: nil)
103
136
  return if abstract_class?
104
137
 
105
138
  if default_scope_override.nil?
@@ -113,20 +146,34 @@ module ActiveRecord
113
146
  end
114
147
  elsif default_scopes.any?
115
148
  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
149
+ default_scopes.inject(relation) do |combined_scope, scope_obj|
150
+ if execute_scope?(all_queries, scope_obj)
151
+ scope = scope_obj.scope.respond_to?(:to_proc) ? scope_obj.scope : scope_obj.scope.method(:call)
152
+
153
+ combined_scope.instance_exec(&scope) || combined_scope
154
+ else
155
+ combined_scope
156
+ end
119
157
  end
120
158
  end
121
159
  end
122
160
  end
123
161
 
162
+ # If all_queries is nil, only execute on select and insert queries.
163
+ #
164
+ # If all_queries is true, check if the default_scope object has
165
+ # all_queries set, then execute on all queries; select, insert, update
166
+ # and delete.
167
+ def execute_scope?(all_queries, default_scope_obj)
168
+ all_queries.nil? || all_queries && default_scope_obj.all_queries
169
+ end
170
+
124
171
  def ignore_default_scope?
125
- ScopeRegistry.value_for(:ignore_default_scope, base_class)
172
+ ScopeRegistry.ignore_default_scope(base_class)
126
173
  end
127
174
 
128
175
  def ignore_default_scope=(ignore)
129
- ScopeRegistry.set_value_for(:ignore_default_scope, base_class, ignore)
176
+ ScopeRegistry.set_ignore_default_scope(base_class, ignore)
130
177
  end
131
178
 
132
179
  # 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
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/per_thread_registry"
3
+ require "active_support/core_ext/module/delegation"
4
4
 
5
5
  module ActiveRecord
6
6
  module Scoping
@@ -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
 
@@ -45,8 +57,8 @@ module ActiveRecord
45
57
  end
46
58
 
47
59
  # This class stores the +:current_scope+ and +:ignore_default_scope+ values
48
- # for different classes. The registry is stored as a thread local, which is
49
- # accessed through +ScopeRegistry.current+.
60
+ # for different classes. The registry is stored as either a thread or fiber
61
+ # local depending on the application configuration.
50
62
  #
51
63
  # This class allows you to store and get the scope values on different
52
64
  # classes and different types of scopes. For example, if you are attempting
@@ -54,52 +66,70 @@ module ActiveRecord
54
66
  # following code:
55
67
  #
56
68
  # registry = ActiveRecord::Scoping::ScopeRegistry
57
- # registry.set_value_for(:current_scope, Board, some_new_scope)
69
+ # registry.set_current_scope(Board, some_new_scope)
58
70
  #
59
71
  # Now when you run:
60
72
  #
61
- # registry.value_for(:current_scope, Board)
62
- #
63
- # You will obtain whatever was defined in +some_new_scope+. The #value_for
64
- # and #set_value_for methods are delegated to the current ScopeRegistry
65
- # object, so the above example code can also be called as:
73
+ # registry.current_scope(Board)
66
74
  #
67
- # ActiveRecord::Scoping::ScopeRegistry.set_value_for(:current_scope,
68
- # Board, some_new_scope)
75
+ # You will obtain whatever was defined in +some_new_scope+.
69
76
  class ScopeRegistry # :nodoc:
70
- extend ActiveSupport::PerThreadRegistry
77
+ class << self
78
+ delegate :current_scope, :set_current_scope, :ignore_default_scope, :set_ignore_default_scope,
79
+ :global_current_scope, :set_global_current_scope, to: :instance
71
80
 
72
- VALID_SCOPE_TYPES = [:current_scope, :ignore_default_scope]
81
+ def instance
82
+ ActiveSupport::IsolatedExecutionState[:active_record_scope_registry] ||= new
83
+ end
84
+ end
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
88
- end
92
+ def current_scope(model, skip_inherited_scope = false)
93
+ value_for(@current_scope, model, skip_inherited_scope)
89
94
  end
90
95
 
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
96
+ def set_current_scope(model, value)
97
+ set_value_for(@current_scope, model, value)
98
+ end
99
+
100
+ def ignore_default_scope(model, skip_inherited_scope = false)
101
+ value_for(@ignore_default_scope, model, skip_inherited_scope)
102
+ end
103
+
104
+ def set_ignore_default_scope(model, value)
105
+ set_value_for(@ignore_default_scope, model, value)
106
+ end
107
+
108
+ def global_current_scope(model, skip_inherited_scope = false)
109
+ value_for(@global_current_scope, model, skip_inherited_scope)
110
+ end
111
+
112
+ def set_global_current_scope(model, value)
113
+ set_value_for(@global_current_scope, model, value)
95
114
  end
96
115
 
97
116
  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"
117
+ # Obtains the value for a given +scope_type+ and +model+.
118
+ def value_for(scope_type, model, skip_inherited_scope = false)
119
+ return scope_type[model.name] if skip_inherited_scope
120
+ klass = model
121
+ base = model.base_class
122
+ while klass <= base
123
+ value = scope_type[klass.name]
124
+ return value if value
125
+ klass = klass.superclass
101
126
  end
102
127
  end
128
+
129
+ # Sets the +value+ for a given +scope_type+ and +model+.
130
+ def set_value_for(scope_type, model, value)
131
+ scope_type[model.name] = value
132
+ end
103
133
  end
104
134
  end
105
135
  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
@@ -20,5 +20,10 @@ module ActiveRecord #:nodoc:
20
20
 
21
21
  super(options)
22
22
  end
23
+
24
+ private
25
+ def attribute_names_for_serialization
26
+ attribute_names
27
+ end
23
28
  end
24
29
  end