activerecord 6.1.6 → 7.0.4

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 (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1314 -975
  3. data/README.rdoc +1 -1
  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 +10 -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 +49 -13
  28. data/lib/active_record/associations/preloader.rb +39 -113
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +3 -3
  31. data/lib/active_record/associations.rb +124 -95
  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 +7 -5
  39. data/lib/active_record/attribute_methods/serialization.rb +57 -19
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +14 -15
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +8 -23
  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 +10 -2
  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 +38 -13
  58. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +80 -24
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +105 -81
  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 +37 -21
  66. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -1
  68. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  69. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  70. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
  71. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
  72. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  75. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  80. data/lib/active_record/connection_adapters/postgresql/quoting.rb +51 -51
  81. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +34 -0
  82. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  83. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  84. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  85. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +37 -19
  86. data/lib/active_record/connection_adapters/postgresql_adapter.rb +208 -107
  87. data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
  88. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
  89. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +28 -16
  90. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +17 -15
  91. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +96 -32
  92. data/lib/active_record/connection_adapters.rb +6 -5
  93. data/lib/active_record/connection_handling.rb +49 -55
  94. data/lib/active_record/core.rb +124 -134
  95. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  96. data/lib/active_record/database_configurations/database_config.rb +12 -9
  97. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  98. data/lib/active_record/database_configurations/url_config.rb +2 -2
  99. data/lib/active_record/database_configurations.rb +15 -32
  100. data/lib/active_record/delegated_type.rb +53 -12
  101. data/lib/active_record/destroy_association_async_job.rb +1 -1
  102. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  103. data/lib/active_record/dynamic_matchers.rb +1 -1
  104. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  105. data/lib/active_record/encryption/cipher.rb +53 -0
  106. data/lib/active_record/encryption/config.rb +44 -0
  107. data/lib/active_record/encryption/configurable.rb +67 -0
  108. data/lib/active_record/encryption/context.rb +35 -0
  109. data/lib/active_record/encryption/contexts.rb +72 -0
  110. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  111. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  112. data/lib/active_record/encryption/encryptable_record.rb +206 -0
  113. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  114. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  115. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  116. data/lib/active_record/encryption/encryptor.rb +155 -0
  117. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  118. data/lib/active_record/encryption/errors.rb +15 -0
  119. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  120. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  121. data/lib/active_record/encryption/key.rb +28 -0
  122. data/lib/active_record/encryption/key_generator.rb +42 -0
  123. data/lib/active_record/encryption/key_provider.rb +46 -0
  124. data/lib/active_record/encryption/message.rb +33 -0
  125. data/lib/active_record/encryption/message_serializer.rb +90 -0
  126. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  127. data/lib/active_record/encryption/properties.rb +76 -0
  128. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  129. data/lib/active_record/encryption/scheme.rb +99 -0
  130. data/lib/active_record/encryption.rb +55 -0
  131. data/lib/active_record/enum.rb +50 -43
  132. data/lib/active_record/errors.rb +67 -4
  133. data/lib/active_record/explain_registry.rb +11 -6
  134. data/lib/active_record/fixture_set/file.rb +15 -1
  135. data/lib/active_record/fixture_set/table_row.rb +41 -6
  136. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  137. data/lib/active_record/fixtures.rb +20 -23
  138. data/lib/active_record/future_result.rb +139 -0
  139. data/lib/active_record/gem_version.rb +4 -4
  140. data/lib/active_record/inheritance.rb +55 -17
  141. data/lib/active_record/insert_all.rb +80 -14
  142. data/lib/active_record/integration.rb +4 -3
  143. data/lib/active_record/internal_metadata.rb +1 -5
  144. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  145. data/lib/active_record/locking/optimistic.rb +10 -9
  146. data/lib/active_record/locking/pessimistic.rb +10 -4
  147. data/lib/active_record/log_subscriber.rb +23 -7
  148. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  149. data/lib/active_record/middleware/database_selector.rb +18 -6
  150. data/lib/active_record/middleware/shard_selector.rb +60 -0
  151. data/lib/active_record/migration/command_recorder.rb +7 -7
  152. data/lib/active_record/migration/compatibility.rb +84 -2
  153. data/lib/active_record/migration/join_table.rb +1 -1
  154. data/lib/active_record/migration.rb +114 -83
  155. data/lib/active_record/model_schema.rb +58 -59
  156. data/lib/active_record/nested_attributes.rb +13 -12
  157. data/lib/active_record/no_touching.rb +3 -3
  158. data/lib/active_record/null_relation.rb +2 -6
  159. data/lib/active_record/persistence.rb +228 -60
  160. data/lib/active_record/query_cache.rb +2 -2
  161. data/lib/active_record/query_logs.rb +138 -0
  162. data/lib/active_record/querying.rb +16 -6
  163. data/lib/active_record/railtie.rb +136 -22
  164. data/lib/active_record/railties/controller_runtime.rb +1 -1
  165. data/lib/active_record/railties/databases.rake +78 -136
  166. data/lib/active_record/readonly_attributes.rb +11 -0
  167. data/lib/active_record/reflection.rb +73 -50
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  169. data/lib/active_record/relation/batches.rb +6 -6
  170. data/lib/active_record/relation/calculations.rb +43 -38
  171. data/lib/active_record/relation/delegation.rb +7 -7
  172. data/lib/active_record/relation/finder_methods.rb +31 -35
  173. data/lib/active_record/relation/merger.rb +20 -13
  174. data/lib/active_record/relation/predicate_builder.rb +1 -6
  175. data/lib/active_record/relation/query_attribute.rb +5 -11
  176. data/lib/active_record/relation/query_methods.rb +276 -67
  177. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  178. data/lib/active_record/relation/spawn_methods.rb +2 -2
  179. data/lib/active_record/relation/where_clause.rb +10 -19
  180. data/lib/active_record/relation.rb +189 -88
  181. data/lib/active_record/result.rb +17 -7
  182. data/lib/active_record/runtime_registry.rb +9 -13
  183. data/lib/active_record/sanitization.rb +17 -12
  184. data/lib/active_record/schema.rb +38 -23
  185. data/lib/active_record/schema_dumper.rb +25 -19
  186. data/lib/active_record/schema_migration.rb +4 -4
  187. data/lib/active_record/scoping/default.rb +60 -13
  188. data/lib/active_record/scoping/named.rb +3 -11
  189. data/lib/active_record/scoping.rb +64 -34
  190. data/lib/active_record/serialization.rb +6 -1
  191. data/lib/active_record/signed_id.rb +3 -3
  192. data/lib/active_record/store.rb +7 -2
  193. data/lib/active_record/suppressor.rb +11 -15
  194. data/lib/active_record/tasks/database_tasks.rb +127 -60
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -13
  197. data/lib/active_record/test_databases.rb +1 -1
  198. data/lib/active_record/test_fixtures.rb +16 -9
  199. data/lib/active_record/timestamp.rb +3 -4
  200. data/lib/active_record/transactions.rb +9 -14
  201. data/lib/active_record/translation.rb +3 -3
  202. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  203. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  204. data/lib/active_record/type/internal/timezone.rb +2 -2
  205. data/lib/active_record/type/serialized.rb +1 -1
  206. data/lib/active_record/type/type_map.rb +17 -20
  207. data/lib/active_record/type.rb +1 -2
  208. data/lib/active_record/validations/associated.rb +4 -4
  209. data/lib/active_record/validations/presence.rb +2 -2
  210. data/lib/active_record/validations/uniqueness.rb +4 -4
  211. data/lib/active_record/version.rb +1 -1
  212. data/lib/active_record.rb +217 -27
  213. data/lib/arel/attributes/attribute.rb +0 -8
  214. data/lib/arel/crud.rb +28 -22
  215. data/lib/arel/delete_manager.rb +18 -4
  216. data/lib/arel/filter_predications.rb +9 -0
  217. data/lib/arel/insert_manager.rb +2 -3
  218. data/lib/arel/nodes/casted.rb +1 -1
  219. data/lib/arel/nodes/delete_statement.rb +12 -13
  220. data/lib/arel/nodes/filter.rb +10 -0
  221. data/lib/arel/nodes/function.rb +1 -0
  222. data/lib/arel/nodes/insert_statement.rb +2 -2
  223. data/lib/arel/nodes/select_core.rb +2 -2
  224. data/lib/arel/nodes/select_statement.rb +2 -2
  225. data/lib/arel/nodes/update_statement.rb +8 -3
  226. data/lib/arel/nodes.rb +1 -0
  227. data/lib/arel/predications.rb +11 -3
  228. data/lib/arel/select_manager.rb +10 -4
  229. data/lib/arel/table.rb +0 -1
  230. data/lib/arel/tree_manager.rb +0 -12
  231. data/lib/arel/update_manager.rb +18 -4
  232. data/lib/arel/visitors/dot.rb +80 -90
  233. data/lib/arel/visitors/mysql.rb +8 -2
  234. data/lib/arel/visitors/postgresql.rb +0 -10
  235. data/lib/arel/visitors/to_sql.rb +58 -2
  236. data/lib/arel.rb +2 -1
  237. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  238. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  239. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  240. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  241. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  242. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  243. metadata +55 -11
@@ -3,7 +3,7 @@
3
3
  module ActiveRecord
4
4
  module Querying
5
5
  QUERYING_METHODS = [
6
- :find, :find_by, :find_by!, :take, :take!, :first, :first!, :last, :last!,
6
+ :find, :find_by, :find_by!, :take, :take!, :sole, :find_sole_by, :first, :first!, :last, :last!,
7
7
  :second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!,
8
8
  :forty_two, :forty_two!, :third_to_last, :third_to_last!, :second_to_last, :second_to_last!,
9
9
  :exists?, :any?, :many?, :none?, :one?,
@@ -12,12 +12,12 @@ module ActiveRecord
12
12
  :create_or_find_by, :create_or_find_by!,
13
13
  :destroy_all, :delete_all, :update_all, :touch_all, :destroy_by, :delete_by,
14
14
  :find_each, :find_in_batches, :in_batches,
15
- :select, :reselect, :order, :reorder, :group, :limit, :offset, :joins, :left_joins, :left_outer_joins,
16
- :where, :rewhere, :preload, :extract_associated, :eager_load, :includes, :from, :lock, :readonly,
15
+ :select, :reselect, :order, :in_order_of, :reorder, :group, :limit, :offset, :joins, :left_joins, :left_outer_joins,
16
+ :where, :rewhere, :invert_where, :preload, :extract_associated, :eager_load, :includes, :from, :lock, :readonly,
17
17
  :and, :or, :annotate, :optimizer_hints, :extending,
18
18
  :having, :create_with, :distinct, :references, :none, :unscope, :merge, :except, :only,
19
19
  :count, :average, :minimum, :maximum, :sum, :calculate,
20
- :pluck, :pick, :ids, :strict_loading
20
+ :pluck, :pick, :ids, :strict_loading, :excluding, :without
21
21
  ].freeze # :nodoc:
22
22
  delegate(*QUERYING_METHODS, to: :all)
23
23
 
@@ -39,12 +39,22 @@ module ActiveRecord
39
39
  # Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
40
40
  # # => [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "author"=>"Quentin"}>, ...]
41
41
  #
42
- # You can use the same string replacement techniques as you can with <tt>ActiveRecord::QueryMethods#where</tt>:
42
+ # You can use the same string replacement techniques as you can with ActiveRecord::QueryMethods#where :
43
43
  #
44
44
  # Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
45
45
  # Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
46
+ #
47
+ # Note that building your own SQL query string from user input may expose your application to
48
+ # injection attacks (https://guides.rubyonrails.org/security.html#sql-injection).
46
49
  def find_by_sql(sql, binds = [], preparable: nil, &block)
47
- result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
50
+ _load_from_sql(_query_by_sql(sql, binds, preparable: preparable), &block)
51
+ end
52
+
53
+ def _query_by_sql(sql, binds = [], preparable: nil, async: false) # :nodoc:
54
+ connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable, async: async)
55
+ end
56
+
57
+ def _load_from_sql(result_set, &block) # :nodoc:
48
58
  column_types = result_set.column_types
49
59
 
50
60
  unless column_types.empty?
@@ -15,6 +15,7 @@ module ActiveRecord
15
15
  # = Active Record Railtie
16
16
  class Railtie < Rails::Railtie # :nodoc:
17
17
  config.active_record = ActiveSupport::OrderedOptions.new
18
+ config.active_record.encryption = ActiveSupport::OrderedOptions.new
18
19
 
19
20
  config.app_generators.orm :active_record, migration: true,
20
21
  timestamps: true
@@ -30,6 +31,10 @@ module ActiveRecord
30
31
  config.active_record.check_schema_cache_dump_version = true
31
32
  config.active_record.maintain_test_schema = true
32
33
  config.active_record.has_many_inversing = false
34
+ config.active_record.sqlite3_production_warning = true
35
+ config.active_record.query_log_tags_enabled = false
36
+ config.active_record.query_log_tags = [ :application ]
37
+ config.active_record.cache_query_log_tags = false
33
38
 
34
39
  config.active_record.queues = ActiveSupport::InheritableOptions.new
35
40
 
@@ -60,7 +65,7 @@ module ActiveRecord
60
65
  console.level = Rails.logger.level
61
66
  Rails.logger.extend ActiveSupport::Logger.broadcast console
62
67
  end
63
- ActiveRecord::Base.verbose_query_logs = false
68
+ ActiveRecord.verbose_query_logs = false
64
69
  end
65
70
 
66
71
  runner do
@@ -70,7 +75,12 @@ module ActiveRecord
70
75
  initializer "active_record.initialize_timezone" do
71
76
  ActiveSupport.on_load(:active_record) do
72
77
  self.time_zone_aware_attributes = true
73
- self.default_timezone = :utc
78
+ end
79
+ end
80
+
81
+ initializer "active_record.postgresql_time_zone_aware_types" do
82
+ ActiveSupport.on_load(:active_record_postgresqladapter) do
83
+ ActiveRecord::Base.time_zone_aware_types << :timestamptz
74
84
  end
75
85
  end
76
86
 
@@ -83,21 +93,13 @@ module ActiveRecord
83
93
  end
84
94
 
85
95
  initializer "active_record.migration_error" do |app|
86
- if config.active_record.delete(:migration_error) == :page_load
96
+ if config.active_record.migration_error == :page_load
87
97
  config.app_middleware.insert_after ::ActionDispatch::Callbacks,
88
98
  ActiveRecord::Migration::CheckPending,
89
99
  file_watcher: app.config.file_watcher
90
100
  end
91
101
  end
92
102
 
93
- initializer "active_record.database_selector" do
94
- if options = config.active_record.delete(:database_selector)
95
- resolver = config.active_record.delete(:database_resolver)
96
- operations = config.active_record.delete(:database_resolver_context)
97
- config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options
98
- end
99
- end
100
-
101
103
  initializer "Check for cache versioning support" do
102
104
  config.after_initialize do |app|
103
105
  ActiveSupport.on_load(:active_record) do
@@ -124,9 +126,9 @@ To keep using the current cache store, you can turn off cache versioning entirel
124
126
  end
125
127
 
126
128
  initializer "active_record.check_schema_cache_dump" do
127
- check_schema_cache_dump_version = config.active_record.delete(:check_schema_cache_dump_version)
129
+ check_schema_cache_dump_version = config.active_record.check_schema_cache_dump_version
128
130
 
129
- if config.active_record.delete(:use_schema_cache_dump)
131
+ if config.active_record.use_schema_cache_dump && !config.active_record.lazily_load_schema_cache
130
132
  config.after_initialize do |app|
131
133
  ActiveSupport.on_load(:active_record) do
132
134
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first
@@ -149,11 +151,12 @@ To keep using the current cache store, you can turn off cache versioning entirel
149
151
  next if current_version.nil?
150
152
 
151
153
  if cache.version != current_version
152
- warn "Ignoring #{filename} because it has expired. The current schema version is #{current_version}, but the one in the cache is #{cache.version}."
154
+ warn "Ignoring #{filename} because it has expired. The current schema version is #{current_version}, but the one in the schema cache file is #{cache.version}."
153
155
  next
154
156
  end
155
157
  end
156
158
 
159
+ Rails.logger.info("Using schema cache file #{filename}")
157
160
  connection_pool.set_schema_cache(cache)
158
161
  end
159
162
  end
@@ -166,10 +169,6 @@ To keep using the current cache store, you can turn off cache versioning entirel
166
169
  if app.config.eager_load
167
170
  begin
168
171
  descendants.each do |model|
169
- # SchemaMigration and InternalMetadata both override `table_exists?`
170
- # to bypass the schema cache, so skip them to avoid the extra queries.
171
- next if model._internal?
172
-
173
172
  # If the schema cache was loaded from a dump, we can use it without connecting
174
173
  schema_cache = model.connection_pool.schema_cache
175
174
 
@@ -201,12 +200,58 @@ To keep using the current cache store, you can turn off cache versioning entirel
201
200
  end
202
201
  end
203
202
 
203
+ SQLITE3_PRODUCTION_WARN = "You are running SQLite in production, this is generally not recommended."\
204
+ " You can disable this warning by setting \"config.active_record.sqlite3_production_warning=false\"."
205
+ initializer "active_record.sqlite3_production_warning" do
206
+ if config.active_record.sqlite3_production_warning && Rails.env.production?
207
+ ActiveSupport.on_load(:active_record_sqlite3adapter) do
208
+ Rails.logger.warn(SQLITE3_PRODUCTION_WARN)
209
+ end
210
+ end
211
+ end
212
+
204
213
  initializer "active_record.set_configs" do |app|
214
+ configs = app.config.active_record
215
+
216
+ config.after_initialize do
217
+ configs.each do |k, v|
218
+ next if k == :encryption
219
+ setter = "#{k}="
220
+ if ActiveRecord.respond_to?(setter)
221
+ ActiveRecord.send(setter, v)
222
+ end
223
+ end
224
+ end
225
+
205
226
  ActiveSupport.on_load(:active_record) do
206
- configs = app.config.active_record
227
+ # Configs used in other initializers
228
+ configs = configs.except(
229
+ :migration_error,
230
+ :database_selector,
231
+ :database_resolver,
232
+ :database_resolver_context,
233
+ :shard_selector,
234
+ :shard_resolver,
235
+ :query_log_tags_enabled,
236
+ :query_log_tags,
237
+ :cache_query_log_tags,
238
+ :sqlite3_production_warning,
239
+ :check_schema_cache_dump_version,
240
+ :use_schema_cache_dump
241
+ )
207
242
 
208
243
  configs.each do |k, v|
209
- send "#{k}=", v
244
+ next if k == :encryption
245
+ setter = "#{k}="
246
+ # Some existing initializers might rely on Active Record configuration
247
+ # being copied from the config object to their actual destination when
248
+ # `ActiveRecord::Base` is loaded.
249
+ # So to preserve backward compatibility we copy the config a second time.
250
+ if ActiveRecord.respond_to?(setter)
251
+ ActiveRecord.send(setter, v)
252
+ else
253
+ send(setter, v)
254
+ end
210
255
  end
211
256
  end
212
257
  end
@@ -215,10 +260,11 @@ To keep using the current cache store, you can turn off cache versioning entirel
215
260
  # and then establishes the connection.
216
261
  initializer "active_record.initialize_database" do
217
262
  ActiveSupport.on_load(:active_record) do
218
- if ActiveRecord::Base.legacy_connection_handling
219
- self.connection_handlers = { writing_role => ActiveRecord::Base.default_connection_handler }
263
+ if ActiveRecord.legacy_connection_handling
264
+ self.connection_handlers = { ActiveRecord.writing_role => ActiveRecord::Base.default_connection_handler }
220
265
  end
221
266
  self.configurations = Rails.application.config.database_configuration
267
+
222
268
  establish_connection
223
269
  end
224
270
  end
@@ -244,6 +290,7 @@ To keep using the current cache store, you can turn off cache versioning entirel
244
290
 
245
291
  initializer "active_record.set_executor_hooks" do
246
292
  ActiveRecord::QueryCache.install_executor_hooks
293
+ ActiveRecord::AsynchronousQueriesTracker.install_executor_hooks
247
294
  end
248
295
 
249
296
  initializer "active_record.add_watchable_files" do |app|
@@ -279,5 +326,72 @@ To keep using the current cache store, you can turn off cache versioning entirel
279
326
  self.signed_id_verifier_secret ||= -> { Rails.application.key_generator.generate_key("active_record/signed_id") }
280
327
  end
281
328
  end
329
+
330
+ initializer "active_record_encryption.configuration" do |app|
331
+ ActiveRecord::Encryption.configure \
332
+ primary_key: app.credentials.dig(:active_record_encryption, :primary_key),
333
+ deterministic_key: app.credentials.dig(:active_record_encryption, :deterministic_key),
334
+ key_derivation_salt: app.credentials.dig(:active_record_encryption, :key_derivation_salt),
335
+ **config.active_record.encryption
336
+
337
+ ActiveSupport.on_load(:active_record) do
338
+ # Support extended queries for deterministic attributes and validations
339
+ if ActiveRecord::Encryption.config.extend_queries
340
+ ActiveRecord::Encryption::ExtendedDeterministicQueries.install_support
341
+ ActiveRecord::Encryption::ExtendedDeterministicUniquenessValidator.install_support
342
+ end
343
+ end
344
+
345
+ ActiveSupport.on_load(:active_record_fixture_set) do
346
+ # Encrypt active record fixtures
347
+ if ActiveRecord::Encryption.config.encrypt_fixtures
348
+ ActiveRecord::Fixture.prepend ActiveRecord::Encryption::EncryptedFixtures
349
+ end
350
+ end
351
+
352
+ # Filtered params
353
+ ActiveSupport.on_load(:action_controller, run_once: true) do
354
+ if ActiveRecord::Encryption.config.add_to_filter_parameters
355
+ ActiveRecord::Encryption.install_auto_filtered_parameters_hook(app)
356
+ end
357
+ end
358
+ end
359
+
360
+ initializer "active_record.query_log_tags_config" do |app|
361
+ config.after_initialize do
362
+ if app.config.active_record.query_log_tags_enabled
363
+ ActiveRecord.query_transformers << ActiveRecord::QueryLogs
364
+ ActiveRecord::QueryLogs.taggings.merge!(
365
+ application: Rails.application.class.name.split("::").first,
366
+ pid: -> { Process.pid },
367
+ socket: -> { ActiveRecord::Base.connection_db_config.socket },
368
+ db_host: -> { ActiveRecord::Base.connection_db_config.host },
369
+ database: -> { ActiveRecord::Base.connection_db_config.database }
370
+ )
371
+
372
+ if app.config.active_record.query_log_tags.present?
373
+ ActiveRecord::QueryLogs.tags = app.config.active_record.query_log_tags
374
+ end
375
+
376
+ if app.config.active_record.cache_query_log_tags
377
+ ActiveRecord::QueryLogs.cache_query_log_tags = true
378
+ end
379
+ end
380
+ end
381
+ end
382
+
383
+ initializer "active_record.unregister_current_scopes_on_unload" do |app|
384
+ config.after_initialize do
385
+ unless app.config.cache_classes
386
+ Rails.autoloaders.main.on_unload do |_cpath, value, _abspath|
387
+ # Conditions are written this way to be robust against custom
388
+ # implementations of value#is_a? or value#<.
389
+ if Class === value && ActiveRecord::Base > value
390
+ value.current_scope = nil
391
+ end
392
+ end
393
+ end
394
+ end
395
+ end
282
396
  end
283
397
  end
@@ -5,7 +5,7 @@ require "active_record/log_subscriber"
5
5
 
6
6
  module ActiveRecord
7
7
  module Railties # :nodoc:
8
- module ControllerRuntime #:nodoc:
8
+ module ControllerRuntime # :nodoc:
9
9
  extend ActiveSupport::Concern
10
10
 
11
11
  module ClassMethods # :nodoc:
@@ -86,19 +86,30 @@ db_namespace = namespace :db do
86
86
 
87
87
  desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
88
88
  task migrate: :load_config do
89
- original_db_config = ActiveRecord::Base.connection_db_config
90
- ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
91
- ActiveRecord::Base.establish_connection(db_config)
89
+ db_configs = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env)
90
+
91
+ if db_configs.size == 1
92
92
  ActiveRecord::Tasks::DatabaseTasks.migrate
93
+ else
94
+ original_db_config = ActiveRecord::Base.connection_db_config
95
+ mapped_versions = ActiveRecord::Tasks::DatabaseTasks.db_configs_with_versions(db_configs)
96
+
97
+ mapped_versions.sort.each do |version, db_configs|
98
+ db_configs.each do |db_config|
99
+ ActiveRecord::Base.establish_connection(db_config)
100
+ ActiveRecord::Tasks::DatabaseTasks.migrate(version)
101
+ end
102
+ end
93
103
  end
104
+
94
105
  db_namespace["_dump"].invoke
95
106
  ensure
96
- ActiveRecord::Base.establish_connection(original_db_config)
107
+ ActiveRecord::Base.establish_connection(original_db_config) if original_db_config
97
108
  end
98
109
 
99
- # IMPORTANT: This task won't dump the schema if ActiveRecord::Base.dump_schema_after_migration is set to false
110
+ # IMPORTANT: This task won't dump the schema if ActiveRecord.dump_schema_after_migration is set to false
100
111
  task :_dump do
101
- if ActiveRecord::Base.dump_schema_after_migration
112
+ if ActiveRecord.dump_schema_after_migration
102
113
  db_namespace["schema:dump"].invoke
103
114
  end
104
115
  # Allow this task to be called as many times as required. An example is the
@@ -108,11 +119,15 @@ db_namespace = namespace :db do
108
119
 
109
120
  namespace :_dump do
110
121
  ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
111
- # IMPORTANT: This task won't dump the schema if ActiveRecord::Base.dump_schema_after_migration is set to false
122
+ # IMPORTANT: This task won't dump the schema if ActiveRecord.dump_schema_after_migration is set to false
112
123
  task name do
113
- if ActiveRecord::Base.dump_schema_after_migration
124
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env, name: name)
125
+
126
+ if ActiveRecord.dump_schema_after_migration && db_config.schema_dump
127
+ ActiveRecord::Base.establish_connection(db_config)
114
128
  db_namespace["schema:dump:#{name}"].invoke
115
129
  end
130
+
116
131
  # Allow this task to be called as many times as required. An example is the
117
132
  # migrate:redo task, which calls other two internally that depend on this one.
118
133
  db_namespace["_dump:#{name}"].reenable
@@ -275,6 +290,7 @@ db_namespace = namespace :db do
275
290
  desc "Rolls the schema back to the previous version (specify steps w/ STEP=n)."
276
291
  task rollback: :load_config do
277
292
  ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:rollback")
293
+ raise "VERSION is not supported - To rollback a specific version, use db:migrate:down" if ENV["VERSION"]
278
294
 
279
295
  step = ENV["STEP"] ? ENV["STEP"].to_i : 1
280
296
 
@@ -290,7 +306,16 @@ db_namespace = namespace :db do
290
306
  db_namespace["_dump"].invoke
291
307
  end
292
308
 
293
- desc "Drops and recreates the database from db/schema.rb for the current environment and loads the seeds."
309
+ namespace :reset do
310
+ task all: ["db:drop", "db:setup"]
311
+
312
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
313
+ desc "Drops and recreates the #{name} database from its schema for the current environment and loads the seeds."
314
+ task name => ["db:drop:#{name}", "db:setup:#{name}"]
315
+ end
316
+ end
317
+
318
+ desc "Drops and recreates all databases from their schema for the current environment and loads the seeds."
294
319
  task reset: [ "db:drop", "db:setup" ]
295
320
 
296
321
  # desc "Retrieves the charset for the current environment's database"
@@ -307,7 +332,7 @@ db_namespace = namespace :db do
307
332
 
308
333
  desc "Retrieves the current schema version number"
309
334
  task version: :load_config do
310
- puts "Current version: #{ActiveRecord::Base.connection.migration_context.current_version}"
335
+ puts "Current version: #{ActiveRecord::Base.connection.schema_version}"
311
336
  end
312
337
 
313
338
  # desc "Raises an error if there are pending migrations"
@@ -349,41 +374,21 @@ db_namespace = namespace :db do
349
374
  end
350
375
  end
351
376
 
352
- desc "Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)"
377
+ namespace :setup do
378
+ task all: ["db:create", :environment, "db:schema:load", :seed]
379
+
380
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
381
+ desc "Creates the #{name} database, loads the schema, and initializes with the seed data (use db:reset:#{name} to also drop the database first)"
382
+ task name => ["db:create:#{name}", :environment, "db:schema:load:#{name}", "db:seed"]
383
+ end
384
+ end
385
+
386
+ desc "Creates all databases, loads all schemas, and initializes with the seed data (use db:reset to also drop all databases first)"
353
387
  task setup: ["db:create", :environment, "db:schema:load", :seed]
354
388
 
355
389
  desc "Runs setup if database does not exist, or runs migrations if it does"
356
390
  task prepare: :load_config do
357
- seed = false
358
-
359
- ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
360
- ActiveRecord::Base.establish_connection(db_config)
361
-
362
- # Skipped when no database
363
- ActiveRecord::Tasks::DatabaseTasks.migrate
364
-
365
- if ActiveRecord::Base.dump_schema_after_migration
366
- ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, ActiveRecord::Base.schema_format)
367
- end
368
- rescue ActiveRecord::NoDatabaseError
369
- config_name = db_config.name
370
- ActiveRecord::Tasks::DatabaseTasks.create_current(db_config.env_name, config_name)
371
-
372
- if File.exist?(ActiveRecord::Tasks::DatabaseTasks.dump_filename(config_name))
373
- ActiveRecord::Tasks::DatabaseTasks.load_schema(
374
- db_config,
375
- ActiveRecord::Base.schema_format,
376
- nil
377
- )
378
- else
379
- ActiveRecord::Tasks::DatabaseTasks.migrate
380
- end
381
-
382
- seed = true
383
- end
384
-
385
- ActiveRecord::Base.establish_connection
386
- ActiveRecord::Tasks::DatabaseTasks.load_seed if seed
391
+ ActiveRecord::Tasks::DatabaseTasks.prepare_all
387
392
  end
388
393
 
389
394
  desc "Loads the seed data from db/seeds.rb"
@@ -447,36 +452,32 @@ db_namespace = namespace :db do
447
452
  end
448
453
 
449
454
  namespace :schema do
450
- desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`)"
455
+ desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`)"
451
456
  task dump: :load_config do
452
457
  ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
453
- ActiveRecord::Base.establish_connection(db_config)
454
- ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config)
458
+ if db_config.schema_dump
459
+ ActiveRecord::Base.establish_connection(db_config)
460
+ schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
461
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, schema_format)
462
+ end
455
463
  end
456
464
 
457
465
  db_namespace["schema:dump"].reenable
458
466
  end
459
467
 
460
- desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) into the database"
468
+ desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) into the database"
461
469
  task load: [:load_config, :check_protected_environments] do
462
- ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ActiveRecord::Base.schema_format, ENV["SCHEMA"])
463
- end
464
-
465
- task load_if_ruby: ["db:create", :environment] do
466
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
467
- Using `bin/rails db:schema:load_if_ruby` is deprecated and will be removed in Rails 7.0.
468
- Configure the format using `config.active_record.schema_format = :ruby` to use `schema.rb` and run `bin/rails db:schema:load` instead.
469
- MSG
470
- db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :ruby
470
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ActiveRecord.schema_format, ENV["SCHEMA"])
471
471
  end
472
472
 
473
473
  namespace :dump do
474
474
  ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
475
- desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) for #{name} database"
475
+ desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) for #{name} database"
476
476
  task name => :load_config do
477
477
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env, name: name)
478
478
  ActiveRecord::Base.establish_connection(db_config)
479
- ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config)
479
+ schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
480
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config, schema_format)
480
481
  db_namespace["schema:dump:#{name}"].reenable
481
482
  end
482
483
  end
@@ -484,10 +485,14 @@ db_namespace = namespace :db do
484
485
 
485
486
  namespace :load do
486
487
  ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
487
- desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) into the #{name} database"
488
- task name => :load_config do
488
+ desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`) into the #{name} database"
489
+ task name => [:load_config, :check_protected_environments] do
490
+ original_db_config = ActiveRecord::Base.connection_db_config
489
491
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env, name: name)
490
- ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ActiveRecord::Base.schema_format, ENV["SCHEMA"])
492
+ schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
493
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
494
+ ensure
495
+ ActiveRecord::Base.establish_connection(original_db_config) if original_db_config
491
496
  end
492
497
  end
493
498
  end
@@ -523,60 +528,17 @@ db_namespace = namespace :db do
523
528
  end
524
529
  end
525
530
 
526
- namespace :structure do
527
- desc "Dumps the database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql"
528
- task dump: :load_config do
529
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
530
- Using `bin/rails db:structure:dump` is deprecated and will be removed in Rails 7.0.
531
- Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:dump` instead.
532
- MSG
533
-
534
- db_namespace["schema:dump"].invoke
535
- db_namespace["structure:dump"].reenable
536
- end
531
+ namespace :encryption do
532
+ desc "Generate a set of keys for configuring Active Record encryption in a given environment"
533
+ task :init do
534
+ puts <<~MSG
535
+ Add this entry to the credentials of the target environment:#{' '}
537
536
 
538
- desc "Recreates the databases from the structure.sql file"
539
- task load: [:load_config, :check_protected_environments] do
540
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
541
- Using `bin/rails db:structure:load` is deprecated and will be removed in Rails 7.0.
542
- Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:load` instead.
537
+ active_record_encryption:
538
+ primary_key: #{SecureRandom.alphanumeric(32)}
539
+ deterministic_key: #{SecureRandom.alphanumeric(32)}
540
+ key_derivation_salt: #{SecureRandom.alphanumeric(32)}
543
541
  MSG
544
- db_namespace["schema:load"].invoke
545
- end
546
-
547
- task load_if_sql: ["db:create", :environment] do
548
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
549
- Using `bin/rails db:structure:load_if_sql` is deprecated and will be removed in Rails 7.0.
550
- Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:load` instead.
551
- MSG
552
- db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :sql
553
- end
554
-
555
- namespace :dump do
556
- ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
557
- desc "Dumps the #{name} database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql"
558
- task name => :load_config do
559
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
560
- Using `bin/rails db:structure:dump:#{name}` is deprecated and will be removed in Rails 7.0.
561
- Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:dump:#{name}` instead.
562
- MSG
563
- db_namespace["schema:dump:#{name}"].invoke
564
- db_namespace["structure:dump:#{name}"].reenable
565
- end
566
- end
567
- end
568
-
569
- namespace :load do
570
- ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
571
- desc "Recreates the #{name} database from the structure.sql file"
572
- task name => :load_config do
573
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
574
- Using `bin/rails db:structure:load:#{name}` is deprecated and will be removed in Rails 7.0.
575
- Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:load:#{name}` instead.
576
- MSG
577
- db_namespace["schema:load:#{name}"].invoke
578
- end
579
- end
580
542
  end
581
543
  end
582
544
 
@@ -586,13 +548,13 @@ db_namespace = namespace :db do
586
548
  db_namespace["test:load_schema"].invoke
587
549
  end
588
550
 
589
- # desc "Recreate the test database from an existent schema file (schema.rb or structure.sql, depending on `config.active_record.schema_format`)"
551
+ # desc "Recreate the test database from an existent schema file (schema.rb or structure.sql, depending on `ENV['SCHEMA_FORMAT']` or `config.active_record.schema_format`)"
590
552
  task load_schema: %w(db:test:purge) do
591
553
  should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
592
554
  ActiveRecord::Schema.verbose = false
593
555
  ActiveRecord::Base.configurations.configs_for(env_name: "test").each do |db_config|
594
- filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(db_config.name)
595
- ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ActiveRecord::Base.schema_format, filename)
556
+ schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
557
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
596
558
  end
597
559
  ensure
598
560
  if should_reconnect
@@ -600,15 +562,6 @@ db_namespace = namespace :db do
600
562
  end
601
563
  end
602
564
 
603
- # desc "Recreate the test database from an existent structure.sql file"
604
- task load_structure: %w(db:test:purge) do
605
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
606
- Using `bin/rails db:test:load_structure` is deprecated and will be removed in Rails 7.0.
607
- Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:test:load_schema` instead.
608
- MSG
609
- db_namespace["test:load_schema"].invoke
610
- end
611
-
612
565
  # desc "Empty the test database"
613
566
  task purge: %w(load_config check_protected_environments) do
614
567
  ActiveRecord::Base.configurations.configs_for(env_name: "test").each do |db_config|
@@ -636,9 +589,9 @@ db_namespace = namespace :db do
636
589
  task name => "db:test:purge:#{name}" do
637
590
  should_reconnect = ActiveRecord::Base.connection_pool.active_connection?
638
591
  ActiveRecord::Schema.verbose = false
639
- filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(name)
640
592
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: "test", name: name)
641
- ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ActiveRecord::Base.schema_format, filename)
593
+ schema_format = ENV.fetch("SCHEMA_FORMAT", ActiveRecord.schema_format).to_sym
594
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, schema_format)
642
595
  ensure
643
596
  if should_reconnect
644
597
  ActiveRecord::Base.establish_connection(ActiveRecord::Tasks::DatabaseTasks.env.to_sym)
@@ -646,17 +599,6 @@ db_namespace = namespace :db do
646
599
  end
647
600
  end
648
601
 
649
- # desc "Recreate the #{name} test database from an existent structure.sql file"
650
- namespace :load_structure do
651
- task name => "db:test:purge:#{name}" do
652
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
653
- Using `bin/rails db:test:load_structure:#{name}` is deprecated and will be removed in Rails 7.0.
654
- Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:test:load_structure:#{name}` instead.
655
- MSG
656
- db_namespace["test:load_schema:#{name}"].invoke
657
- end
658
- end
659
-
660
602
  # desc "Empty the #{name} test database"
661
603
  namespace :purge do
662
604
  task name => %w(load_config check_protected_environments) do
@@ -11,6 +11,17 @@ module ActiveRecord
11
11
  module ClassMethods
12
12
  # Attributes listed as readonly will be used to create a new record but update operations will
13
13
  # ignore these fields.
14
+ #
15
+ # You can assign a new value to a readonly attribute, but it will be ignored when the record is updated.
16
+ #
17
+ # ==== Examples
18
+ #
19
+ # class Post < ActiveRecord::Base
20
+ # attr_readonly :title
21
+ # end
22
+ #
23
+ # post = Post.create!(title: "Introducing Ruby on Rails!")
24
+ # post.update(title: "a different title") # change to title will be ignored
14
25
  def attr_readonly(*attributes)
15
26
  self._attr_readonly = Set.new(attributes.map(&:to_s)) + (_attr_readonly || [])
16
27
  end