activerecord 6.1.7.7 → 7.0.0.alpha1

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

Potentially problematic release.


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

Files changed (220) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +726 -1389
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +0 -10
  7. data/lib/active_record/associations/association.rb +31 -9
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +8 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  13. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  14. data/lib/active_record/associations/builder/has_many.rb +3 -2
  15. data/lib/active_record/associations/builder/has_one.rb +2 -1
  16. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  17. data/lib/active_record/associations/collection_association.rb +14 -23
  18. data/lib/active_record/associations/collection_proxy.rb +8 -3
  19. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  20. data/lib/active_record/associations/has_many_association.rb +1 -1
  21. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  22. data/lib/active_record/associations/has_one_association.rb +10 -7
  23. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  24. data/lib/active_record/associations/preloader/association.rb +161 -47
  25. data/lib/active_record/associations/preloader/batch.rb +51 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +37 -11
  28. data/lib/active_record/associations/preloader.rb +46 -110
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +1 -1
  31. data/lib/active_record/associations.rb +76 -81
  32. data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +41 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +7 -5
  39. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +6 -9
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +3 -18
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/coders/yaml_column.rb +2 -14
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +12 -14
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +3 -3
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +112 -66
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
  61. data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -23
  62. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
  63. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
  64. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  65. data/lib/active_record/connection_adapters/pool_config.rb +1 -3
  66. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -14
  67. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  70. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  71. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  74. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  75. data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -32
  76. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
  78. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
  79. data/lib/active_record/connection_adapters/postgresql_adapter.rb +159 -102
  80. data/lib/active_record/connection_adapters/schema_cache.rb +36 -37
  81. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -19
  82. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  83. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  84. data/lib/active_record/connection_adapters.rb +6 -5
  85. data/lib/active_record/connection_handling.rb +20 -38
  86. data/lib/active_record/core.rb +111 -125
  87. data/lib/active_record/database_configurations/connection_url_resolver.rb +0 -1
  88. data/lib/active_record/database_configurations/database_config.rb +12 -0
  89. data/lib/active_record/database_configurations/hash_config.rb +27 -1
  90. data/lib/active_record/database_configurations/url_config.rb +2 -2
  91. data/lib/active_record/database_configurations.rb +17 -9
  92. data/lib/active_record/delegated_type.rb +33 -11
  93. data/lib/active_record/destroy_association_async_job.rb +1 -1
  94. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  95. data/lib/active_record/dynamic_matchers.rb +1 -1
  96. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  97. data/lib/active_record/encryption/cipher.rb +53 -0
  98. data/lib/active_record/encryption/config.rb +44 -0
  99. data/lib/active_record/encryption/configurable.rb +61 -0
  100. data/lib/active_record/encryption/context.rb +35 -0
  101. data/lib/active_record/encryption/contexts.rb +72 -0
  102. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  103. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  104. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  105. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  106. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  107. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  108. data/lib/active_record/encryption/encryptor.rb +155 -0
  109. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  110. data/lib/active_record/encryption/errors.rb +15 -0
  111. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  112. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
  113. data/lib/active_record/encryption/key.rb +28 -0
  114. data/lib/active_record/encryption/key_generator.rb +42 -0
  115. data/lib/active_record/encryption/key_provider.rb +46 -0
  116. data/lib/active_record/encryption/message.rb +33 -0
  117. data/lib/active_record/encryption/message_serializer.rb +80 -0
  118. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  119. data/lib/active_record/encryption/properties.rb +76 -0
  120. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  121. data/lib/active_record/encryption/scheme.rb +99 -0
  122. data/lib/active_record/encryption.rb +55 -0
  123. data/lib/active_record/enum.rb +41 -41
  124. data/lib/active_record/errors.rb +66 -3
  125. data/lib/active_record/fixture_set/file.rb +15 -1
  126. data/lib/active_record/fixture_set/table_row.rb +40 -5
  127. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  128. data/lib/active_record/fixtures.rb +16 -11
  129. data/lib/active_record/future_result.rb +139 -0
  130. data/lib/active_record/gem_version.rb +4 -4
  131. data/lib/active_record/inheritance.rb +55 -17
  132. data/lib/active_record/insert_all.rb +34 -5
  133. data/lib/active_record/integration.rb +1 -1
  134. data/lib/active_record/internal_metadata.rb +1 -5
  135. data/lib/active_record/locking/optimistic.rb +10 -9
  136. data/lib/active_record/log_subscriber.rb +6 -2
  137. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  138. data/lib/active_record/middleware/database_selector.rb +8 -3
  139. data/lib/active_record/migration/command_recorder.rb +4 -4
  140. data/lib/active_record/migration/compatibility.rb +89 -10
  141. data/lib/active_record/migration/join_table.rb +1 -1
  142. data/lib/active_record/migration.rb +109 -79
  143. data/lib/active_record/model_schema.rb +45 -31
  144. data/lib/active_record/nested_attributes.rb +3 -3
  145. data/lib/active_record/no_touching.rb +2 -2
  146. data/lib/active_record/null_relation.rb +2 -6
  147. data/lib/active_record/persistence.rb +134 -45
  148. data/lib/active_record/query_cache.rb +2 -2
  149. data/lib/active_record/query_logs.rb +203 -0
  150. data/lib/active_record/querying.rb +15 -5
  151. data/lib/active_record/railtie.rb +117 -17
  152. data/lib/active_record/railties/controller_runtime.rb +1 -1
  153. data/lib/active_record/railties/databases.rake +72 -48
  154. data/lib/active_record/readonly_attributes.rb +11 -0
  155. data/lib/active_record/reflection.rb +45 -44
  156. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  157. data/lib/active_record/relation/batches.rb +3 -3
  158. data/lib/active_record/relation/calculations.rb +39 -26
  159. data/lib/active_record/relation/delegation.rb +6 -6
  160. data/lib/active_record/relation/finder_methods.rb +31 -22
  161. data/lib/active_record/relation/merger.rb +20 -13
  162. data/lib/active_record/relation/predicate_builder.rb +1 -6
  163. data/lib/active_record/relation/query_attribute.rb +5 -11
  164. data/lib/active_record/relation/query_methods.rb +230 -49
  165. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  166. data/lib/active_record/relation/spawn_methods.rb +2 -2
  167. data/lib/active_record/relation/where_clause.rb +8 -4
  168. data/lib/active_record/relation.rb +166 -77
  169. data/lib/active_record/result.rb +17 -2
  170. data/lib/active_record/runtime_registry.rb +2 -4
  171. data/lib/active_record/sanitization.rb +11 -7
  172. data/lib/active_record/schema_dumper.rb +3 -3
  173. data/lib/active_record/schema_migration.rb +0 -4
  174. data/lib/active_record/scoping/default.rb +61 -12
  175. data/lib/active_record/scoping/named.rb +3 -11
  176. data/lib/active_record/scoping.rb +40 -22
  177. data/lib/active_record/serialization.rb +1 -1
  178. data/lib/active_record/signed_id.rb +1 -1
  179. data/lib/active_record/store.rb +1 -6
  180. data/lib/active_record/tasks/database_tasks.rb +106 -22
  181. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  182. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
  183. data/lib/active_record/test_databases.rb +1 -1
  184. data/lib/active_record/test_fixtures.rb +9 -13
  185. data/lib/active_record/timestamp.rb +3 -4
  186. data/lib/active_record/transactions.rb +9 -14
  187. data/lib/active_record/translation.rb +2 -2
  188. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  189. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  190. data/lib/active_record/type/internal/timezone.rb +2 -2
  191. data/lib/active_record/type/serialized.rb +1 -1
  192. data/lib/active_record/type/type_map.rb +17 -20
  193. data/lib/active_record/type.rb +1 -2
  194. data/lib/active_record/validations/associated.rb +1 -1
  195. data/lib/active_record.rb +170 -2
  196. data/lib/arel/attributes/attribute.rb +0 -8
  197. data/lib/arel/crud.rb +18 -22
  198. data/lib/arel/delete_manager.rb +2 -4
  199. data/lib/arel/insert_manager.rb +2 -3
  200. data/lib/arel/nodes/casted.rb +1 -1
  201. data/lib/arel/nodes/delete_statement.rb +8 -13
  202. data/lib/arel/nodes/insert_statement.rb +2 -2
  203. data/lib/arel/nodes/select_core.rb +2 -2
  204. data/lib/arel/nodes/select_statement.rb +2 -2
  205. data/lib/arel/nodes/update_statement.rb +3 -2
  206. data/lib/arel/predications.rb +1 -1
  207. data/lib/arel/select_manager.rb +10 -4
  208. data/lib/arel/table.rb +0 -1
  209. data/lib/arel/tree_manager.rb +0 -12
  210. data/lib/arel/update_manager.rb +2 -4
  211. data/lib/arel/visitors/dot.rb +80 -90
  212. data/lib/arel/visitors/mysql.rb +6 -1
  213. data/lib/arel/visitors/postgresql.rb +0 -10
  214. data/lib/arel/visitors/to_sql.rb +43 -2
  215. data/lib/arel.rb +1 -1
  216. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  217. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  218. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  219. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  220. metadata +55 -17
@@ -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"
@@ -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"
@@ -450,8 +455,10 @@ db_namespace = namespace :db do
450
455
  desc "Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `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
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config)
461
+ end
455
462
  end
456
463
 
457
464
  db_namespace["schema:dump"].reenable
@@ -459,7 +466,7 @@ db_namespace = namespace :db do
459
466
 
460
467
  desc "Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) into the database"
461
468
  task load: [:load_config, :check_protected_environments] do
462
- ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ActiveRecord::Base.schema_format, ENV["SCHEMA"])
469
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_current(ActiveRecord.schema_format, ENV["SCHEMA"])
463
470
  end
464
471
 
465
472
  task load_if_ruby: ["db:create", :environment] do
@@ -467,7 +474,7 @@ db_namespace = namespace :db do
467
474
  Using `bin/rails db:schema:load_if_ruby` is deprecated and will be removed in Rails 7.0.
468
475
  Configure the format using `config.active_record.schema_format = :ruby` to use `schema.rb` and run `bin/rails db:schema:load` instead.
469
476
  MSG
470
- db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :ruby
477
+ db_namespace["schema:load"].invoke if ActiveRecord.schema_format == :ruby
471
478
  end
472
479
 
473
480
  namespace :dump do
@@ -486,8 +493,11 @@ db_namespace = namespace :db do
486
493
  ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |name|
487
494
  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
495
  task name => :load_config do
496
+ original_db_config = ActiveRecord::Base.connection_db_config
489
497
  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"])
498
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ActiveRecord.schema_format, ENV["SCHEMA"])
499
+ ensure
500
+ ActiveRecord::Base.establish_connection(original_db_config) if original_db_config
491
501
  end
492
502
  end
493
503
  end
@@ -549,7 +559,7 @@ db_namespace = namespace :db do
549
559
  Using `bin/rails db:structure:load_if_sql` is deprecated and will be removed in Rails 7.0.
550
560
  Configure the format using `config.active_record.schema_format = :sql` to use `structure.sql` and run `bin/rails db:schema:load` instead.
551
561
  MSG
552
- db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :sql
562
+ db_namespace["schema:load"].invoke if ActiveRecord.schema_format == :sql
553
563
  end
554
564
 
555
565
  namespace :dump do
@@ -580,6 +590,20 @@ db_namespace = namespace :db do
580
590
  end
581
591
  end
582
592
 
593
+ namespace :encryption do
594
+ desc "Generate a set of keys for configuring Active Record encryption in a given environment"
595
+ task :init do
596
+ puts <<~MSG
597
+ Add this entry to the credentials of the target environment:#{' '}
598
+
599
+ active_record_encryption:
600
+ primary_key: #{SecureRandom.alphanumeric(32)}
601
+ deterministic_key: #{SecureRandom.alphanumeric(32)}
602
+ key_derivation_salt: #{SecureRandom.alphanumeric(32)}
603
+ MSG
604
+ end
605
+ end
606
+
583
607
  namespace :test do
584
608
  # desc "Recreate the test database from the current schema"
585
609
  task load: %w(db:test:purge) do
@@ -592,7 +616,7 @@ db_namespace = namespace :db do
592
616
  ActiveRecord::Schema.verbose = false
593
617
  ActiveRecord::Base.configurations.configs_for(env_name: "test").each do |db_config|
594
618
  filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(db_config.name)
595
- ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ActiveRecord::Base.schema_format, filename)
619
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ActiveRecord.schema_format, filename)
596
620
  end
597
621
  ensure
598
622
  if should_reconnect
@@ -638,7 +662,7 @@ db_namespace = namespace :db do
638
662
  ActiveRecord::Schema.verbose = false
639
663
  filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(name)
640
664
  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)
665
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(db_config, ActiveRecord.schema_format, filename)
642
666
  ensure
643
667
  if should_reconnect
644
668
  ActiveRecord::Base.establish_connection(ActiveRecord::Tasks::DatabaseTasks.env.to_sym)
@@ -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
@@ -115,7 +115,7 @@ module ActiveRecord
115
115
  reflections[association.to_s]
116
116
  end
117
117
 
118
- def _reflect_on_association(association) #:nodoc:
118
+ def _reflect_on_association(association) # :nodoc:
119
119
  _reflections[association.to_s]
120
120
  end
121
121
 
@@ -194,9 +194,9 @@ module ActiveRecord
194
194
  klass_scope
195
195
  end
196
196
 
197
- def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
197
+ def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
198
198
  if scope
199
- [scope_for(build_scope(table, predicate_builder, klass))]
199
+ [scope_for(build_scope(table, predicate_builder, klass), record)]
200
200
  else
201
201
  []
202
202
  end
@@ -237,7 +237,7 @@ module ActiveRecord
237
237
  end
238
238
  end
239
239
 
240
- # This shit is nasty. We need to avoid the following situation:
240
+ # We need to avoid the following situation:
241
241
  #
242
242
  # * An associated record is deleted via record.destroy
243
243
  # * Hence the callbacks run, and they find a belongs_to on the record with a
@@ -306,6 +306,12 @@ module ActiveRecord
306
306
  def primary_key(klass)
307
307
  klass.primary_key || raise(UnknownPrimaryKey.new(klass))
308
308
  end
309
+
310
+ def ensure_option_not_given_as_class!(option_name)
311
+ if options[option_name] && options[option_name].class == Class
312
+ raise ArgumentError, "A class was passed to `:#{option_name}` but we are expecting a string."
313
+ end
314
+ end
309
315
  end
310
316
 
311
317
  # Base class for AggregateReflection and AssociationReflection. Objects of
@@ -392,7 +398,7 @@ module ActiveRecord
392
398
 
393
399
  # Holds all the metadata about an aggregation as it was specified in the
394
400
  # Active Record class.
395
- class AggregateReflection < MacroReflection #:nodoc:
401
+ class AggregateReflection < MacroReflection # :nodoc:
396
402
  def mapping
397
403
  mapping = options[:mapping] || [name, name]
398
404
  mapping.first.is_a?(Array) ? mapping : [mapping]
@@ -401,12 +407,29 @@ module ActiveRecord
401
407
 
402
408
  # Holds all the metadata about an association as it was specified in the
403
409
  # Active Record class.
404
- class AssociationReflection < MacroReflection #:nodoc:
410
+ class AssociationReflection < MacroReflection # :nodoc:
405
411
  def compute_class(name)
406
412
  if polymorphic?
407
413
  raise ArgumentError, "Polymorphic associations do not support computing the class."
408
414
  end
409
- active_record.send(:compute_type, name)
415
+
416
+ msg = <<-MSG.squish
417
+ Rails couldn't find a valid model for #{name} association.
418
+ Please provide the :class_name option on the association declaration.
419
+ If :class_name is already provided, make sure it's an ActiveRecord::Base subclass.
420
+ MSG
421
+
422
+ begin
423
+ klass = active_record.send(:compute_type, name)
424
+
425
+ unless klass < ActiveRecord::Base
426
+ raise ArgumentError, msg
427
+ end
428
+
429
+ klass
430
+ rescue NameError
431
+ raise NameError, msg
432
+ end
410
433
  end
411
434
 
412
435
  attr_reader :type, :foreign_type
@@ -416,11 +439,8 @@ module ActiveRecord
416
439
  super
417
440
  @type = -(options[:foreign_type]&.to_s || "#{options[:as]}_type") if options[:as]
418
441
  @foreign_type = -(options[:foreign_type]&.to_s || "#{name}_type") if options[:polymorphic]
419
- @constructable = calculate_constructable(macro, options)
420
442
 
421
- if options[:class_name] && options[:class_name].class == Class
422
- raise ArgumentError, "A class was passed to `:class_name` but we are expecting a string."
423
- end
443
+ ensure_option_not_given_as_class!(:class_name)
424
444
  end
425
445
 
426
446
  def association_scope_cache(klass, owner, &block)
@@ -431,10 +451,6 @@ module ActiveRecord
431
451
  klass.cached_find_by_statement(key, &block)
432
452
  end
433
453
 
434
- def constructable? # :nodoc:
435
- @constructable
436
- end
437
-
438
454
  def join_table
439
455
  @join_table ||= -(options[:join_table]&.to_s || derive_join_table)
440
456
  end
@@ -467,18 +483,17 @@ module ActiveRecord
467
483
  check_validity_of_inverse!
468
484
  end
469
485
 
470
- def check_preloadable!
486
+ def check_eager_loadable!
471
487
  return unless scope
472
488
 
473
489
  unless scope.arity == 0
474
490
  raise ArgumentError, <<-MSG.squish
475
491
  The association scope '#{name}' is instance dependent (the scope
476
- block takes an argument). Preloading instance dependent scopes is
477
- not supported.
492
+ block takes an argument). Eager loading instance dependent scopes
493
+ is not supported.
478
494
  MSG
479
495
  end
480
496
  end
481
- alias :check_eager_loadable! :check_preloadable!
482
497
 
483
498
  def join_id_for(owner) # :nodoc:
484
499
  owner[join_foreign_key]
@@ -563,9 +578,6 @@ module ActiveRecord
563
578
  options[:polymorphic]
564
579
  end
565
580
 
566
- VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to]
567
- INVALID_AUTOMATIC_INVERSE_OPTIONS = [:through, :foreign_key]
568
-
569
581
  def add_as_source(seed)
570
582
  seed
571
583
  end
@@ -583,10 +595,6 @@ module ActiveRecord
583
595
  end
584
596
 
585
597
  private
586
- def calculate_constructable(macro, options)
587
- true
588
- end
589
-
590
598
  # Attempts to find the inverse association name automatically.
591
599
  # If it cannot find a suitable inverse association name, it returns
592
600
  # +nil+.
@@ -639,8 +647,8 @@ module ActiveRecord
639
647
  # inverse, so we exclude reflections with scopes.
640
648
  def can_find_inverse_of_automatically?(reflection)
641
649
  reflection.options[:inverse_of] != false &&
642
- VALID_AUTOMATIC_INVERSE_MACROS.include?(reflection.macro) &&
643
- !INVALID_AUTOMATIC_INVERSE_OPTIONS.any? { |opt| reflection.options[opt] } &&
650
+ !reflection.options[:through] &&
651
+ !reflection.options[:foreign_key] &&
644
652
  !reflection.scope
645
653
  end
646
654
 
@@ -656,7 +664,7 @@ module ActiveRecord
656
664
  elsif options[:as]
657
665
  "#{options[:as]}_id"
658
666
  else
659
- active_record.name.foreign_key
667
+ active_record.model_name.to_s.foreign_key
660
668
  end
661
669
  end
662
670
 
@@ -691,11 +699,6 @@ module ActiveRecord
691
699
  Associations::HasOneAssociation
692
700
  end
693
701
  end
694
-
695
- private
696
- def calculate_constructable(macro, options)
697
- !options[:through]
698
- end
699
702
  end
700
703
 
701
704
  class BelongsToReflection < AssociationReflection # :nodoc:
@@ -736,10 +739,6 @@ module ActiveRecord
736
739
  def can_find_inverse_of_automatically?(_)
737
740
  !polymorphic? && super
738
741
  end
739
-
740
- def calculate_constructable(macro, options)
741
- !polymorphic?
742
- end
743
742
  end
744
743
 
745
744
  class HasAndBelongsToManyReflection < AssociationReflection # :nodoc:
@@ -752,7 +751,7 @@ module ActiveRecord
752
751
 
753
752
  # Holds all the metadata about a :through association as it was specified
754
753
  # in the Active Record class.
755
- class ThroughReflection < AbstractReflection #:nodoc:
754
+ class ThroughReflection < AbstractReflection # :nodoc:
756
755
  delegate :foreign_key, :foreign_type, :association_foreign_key, :join_id_for, :type,
757
756
  :active_record_primary_key, :join_foreign_key, to: :source_reflection
758
757
 
@@ -760,6 +759,8 @@ module ActiveRecord
760
759
  @delegate_reflection = delegate_reflection
761
760
  @klass = delegate_reflection.options[:anonymous_class]
762
761
  @source_reflection_name = delegate_reflection.options[:source]
762
+
763
+ ensure_option_not_given_as_class!(:source_type)
763
764
  end
764
765
 
765
766
  def through_reflection?
@@ -840,8 +841,8 @@ module ActiveRecord
840
841
  source_reflection.scopes + super
841
842
  end
842
843
 
843
- def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
844
- source_reflection.join_scopes(table, predicate_builder, klass) + super
844
+ def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
845
+ source_reflection.join_scopes(table, predicate_builder, klass, record) + super
845
846
  end
846
847
 
847
848
  def has_scope?
@@ -1013,9 +1014,9 @@ module ActiveRecord
1013
1014
  @previous_reflection = previous_reflection
1014
1015
  end
1015
1016
 
1016
- def join_scopes(table, predicate_builder, klass = self.klass) # :nodoc:
1017
- scopes = @previous_reflection.join_scopes(table, predicate_builder) + super
1018
- scopes << build_scope(table, predicate_builder, klass).instance_exec(nil, &source_type_scope)
1017
+ def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
1018
+ scopes = @previous_reflection.join_scopes(table, predicate_builder, record) + super
1019
+ scopes << build_scope(table, predicate_builder, klass).instance_exec(record, &source_type_scope)
1019
1020
  end
1020
1021
 
1021
1022
  def constraints
@@ -5,13 +5,27 @@ module ActiveRecord
5
5
  class BatchEnumerator
6
6
  include Enumerable
7
7
 
8
- def initialize(of: 1000, start: nil, finish: nil, relation:) #:nodoc:
8
+ def initialize(of: 1000, start: nil, finish: nil, relation:) # :nodoc:
9
9
  @of = of
10
10
  @relation = relation
11
11
  @start = start
12
12
  @finish = finish
13
13
  end
14
14
 
15
+ # The primary key value from which the BatchEnumerator starts, inclusive of the value.
16
+ attr_reader :start
17
+
18
+ # The primary key value at which the BatchEnumerator ends, inclusive of the value.
19
+ attr_reader :finish
20
+
21
+ # The relation from which the BatchEnumerator yields batches.
22
+ attr_reader :relation
23
+
24
+ # The size of the batches yielded by the BatchEnumerator.
25
+ def batch_size
26
+ @of
27
+ end
28
+
15
29
  # Looping through a collection of records from the database (using the
16
30
  # +all+ method, for example) is very inefficient since it will try to
17
31
  # instantiate all the objects at once.
@@ -33,11 +47,11 @@ module ActiveRecord
33
47
  # Person.in_batches.each_record.with_index do |person, index|
34
48
  # person.award_trophy(index + 1)
35
49
  # end
36
- def each_record
50
+ def each_record(&block)
37
51
  return to_enum(:each_record) unless block_given?
38
52
 
39
53
  @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: true).each do |relation|
40
- relation.records.each { |record| yield record }
54
+ relation.records.each(&block)
41
55
  end
42
56
  end
43
57
 
@@ -75,9 +89,9 @@ module ActiveRecord
75
89
  # Person.in_batches.each do |relation|
76
90
  # relation.update_all(awesome: true)
77
91
  # end
78
- def each
92
+ def each(&block)
79
93
  enum = @relation.to_enum(:in_batches, of: @of, start: @start, finish: @finish, load: false)
80
- return enum.each { |relation| yield relation } if block_given?
94
+ return enum.each(&block) if block_given?
81
95
  enum
82
96
  end
83
97
  end
@@ -65,10 +65,10 @@ module ActiveRecord
65
65
  #
66
66
  # NOTE: By its nature, batch processing is subject to race conditions if
67
67
  # other processes are modifying the database.
68
- def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc)
68
+ def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc, &block)
69
69
  if block_given?
70
70
  find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do |records|
71
- records.each { |record| yield record }
71
+ records.each(&block)
72
72
  end
73
73
  else
74
74
  enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore, order: order) do
@@ -284,7 +284,7 @@ module ActiveRecord
284
284
  end
285
285
 
286
286
  def act_on_ignored_order(error_on_ignore)
287
- raise_error = (error_on_ignore.nil? ? klass.error_on_ignored_order : error_on_ignore)
287
+ raise_error = (error_on_ignore.nil? ? ActiveRecord.error_on_ignored_order : error_on_ignore)
288
288
 
289
289
  if raise_error
290
290
  raise ArgumentError.new(ORDER_IGNORE_MESSAGE)