activerecord 6.0.0.beta3 → 6.0.2.rc2

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +466 -9
  3. data/README.rdoc +3 -1
  4. data/lib/active_record.rb +0 -1
  5. data/lib/active_record/association_relation.rb +15 -6
  6. data/lib/active_record/associations.rb +4 -3
  7. data/lib/active_record/associations/association.rb +10 -2
  8. data/lib/active_record/associations/builder/association.rb +14 -18
  9. data/lib/active_record/associations/builder/belongs_to.rb +5 -2
  10. data/lib/active_record/associations/builder/collection_association.rb +5 -15
  11. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
  12. data/lib/active_record/associations/builder/has_many.rb +2 -0
  13. data/lib/active_record/associations/builder/has_one.rb +35 -1
  14. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  15. data/lib/active_record/associations/collection_association.rb +6 -2
  16. data/lib/active_record/associations/collection_proxy.rb +2 -2
  17. data/lib/active_record/associations/has_many_through_association.rb +4 -11
  18. data/lib/active_record/associations/join_dependency.rb +14 -9
  19. data/lib/active_record/associations/join_dependency/join_association.rb +12 -3
  20. data/lib/active_record/associations/preloader.rb +13 -8
  21. data/lib/active_record/associations/preloader/association.rb +34 -30
  22. data/lib/active_record/associations/preloader/through_association.rb +48 -28
  23. data/lib/active_record/attribute_methods.rb +3 -53
  24. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  25. data/lib/active_record/attribute_methods/dirty.rb +47 -14
  26. data/lib/active_record/attribute_methods/primary_key.rb +7 -15
  27. data/lib/active_record/attribute_methods/query.rb +2 -3
  28. data/lib/active_record/attribute_methods/read.rb +3 -9
  29. data/lib/active_record/attribute_methods/write.rb +6 -12
  30. data/lib/active_record/attributes.rb +13 -0
  31. data/lib/active_record/autosave_association.rb +21 -7
  32. data/lib/active_record/base.rb +0 -1
  33. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -11
  34. data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
  35. data/lib/active_record/connection_adapters/abstract/database_statements.rb +88 -61
  36. data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -4
  37. data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
  38. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +4 -7
  39. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
  40. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +79 -22
  41. data/lib/active_record/connection_adapters/abstract/transaction.rb +12 -4
  42. data/lib/active_record/connection_adapters/abstract_adapter.rb +111 -33
  43. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +78 -73
  44. data/lib/active_record/connection_adapters/column.rb +17 -13
  45. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  46. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +2 -2
  47. data/lib/active_record/connection_adapters/mysql/database_statements.rb +48 -8
  48. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  49. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -5
  50. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +9 -6
  51. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  52. data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
  53. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
  54. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +8 -2
  55. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  56. data/lib/active_record/connection_adapters/postgresql/quoting.rb +39 -2
  57. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +34 -38
  58. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
  59. data/lib/active_record/connection_adapters/postgresql_adapter.rb +67 -26
  60. data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
  61. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  62. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +120 -0
  63. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
  64. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +2 -2
  65. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -114
  66. data/lib/active_record/connection_handling.rb +31 -13
  67. data/lib/active_record/core.rb +23 -24
  68. data/lib/active_record/database_configurations.rb +73 -44
  69. data/lib/active_record/database_configurations/hash_config.rb +11 -11
  70. data/lib/active_record/database_configurations/url_config.rb +12 -12
  71. data/lib/active_record/dynamic_matchers.rb +1 -1
  72. data/lib/active_record/enum.rb +15 -0
  73. data/lib/active_record/errors.rb +1 -1
  74. data/lib/active_record/fixtures.rb +11 -6
  75. data/lib/active_record/gem_version.rb +2 -2
  76. data/lib/active_record/insert_all.rb +179 -0
  77. data/lib/active_record/integration.rb +13 -1
  78. data/lib/active_record/internal_metadata.rb +5 -1
  79. data/lib/active_record/locking/optimistic.rb +3 -4
  80. data/lib/active_record/log_subscriber.rb +1 -1
  81. data/lib/active_record/middleware/database_selector.rb +3 -3
  82. data/lib/active_record/middleware/database_selector/resolver.rb +4 -6
  83. data/lib/active_record/migration.rb +62 -44
  84. data/lib/active_record/migration/command_recorder.rb +28 -14
  85. data/lib/active_record/migration/compatibility.rb +10 -0
  86. data/lib/active_record/model_schema.rb +3 -0
  87. data/lib/active_record/persistence.rb +206 -13
  88. data/lib/active_record/querying.rb +17 -12
  89. data/lib/active_record/railtie.rb +0 -1
  90. data/lib/active_record/railties/databases.rake +127 -25
  91. data/lib/active_record/reflection.rb +3 -3
  92. data/lib/active_record/relation.rb +99 -20
  93. data/lib/active_record/relation/calculations.rb +38 -40
  94. data/lib/active_record/relation/delegation.rb +22 -30
  95. data/lib/active_record/relation/finder_methods.rb +17 -12
  96. data/lib/active_record/relation/merger.rb +11 -16
  97. data/lib/active_record/relation/query_methods.rb +228 -76
  98. data/lib/active_record/relation/where_clause.rb +9 -5
  99. data/lib/active_record/sanitization.rb +33 -4
  100. data/lib/active_record/schema.rb +1 -1
  101. data/lib/active_record/schema_dumper.rb +10 -1
  102. data/lib/active_record/schema_migration.rb +1 -1
  103. data/lib/active_record/scoping/default.rb +6 -7
  104. data/lib/active_record/scoping/named.rb +3 -2
  105. data/lib/active_record/statement_cache.rb +2 -2
  106. data/lib/active_record/store.rb +48 -0
  107. data/lib/active_record/table_metadata.rb +9 -13
  108. data/lib/active_record/tasks/database_tasks.rb +109 -6
  109. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
  110. data/lib/active_record/test_databases.rb +1 -16
  111. data/lib/active_record/test_fixtures.rb +1 -0
  112. data/lib/active_record/timestamp.rb +26 -16
  113. data/lib/active_record/touch_later.rb +4 -2
  114. data/lib/active_record/transactions.rb +56 -46
  115. data/lib/active_record/type_caster/connection.rb +16 -10
  116. data/lib/active_record/validations.rb +1 -0
  117. data/lib/active_record/validations/uniqueness.rb +3 -5
  118. data/lib/arel.rb +12 -5
  119. data/lib/arel/insert_manager.rb +3 -3
  120. data/lib/arel/nodes.rb +2 -1
  121. data/lib/arel/nodes/comment.rb +29 -0
  122. data/lib/arel/nodes/select_core.rb +16 -12
  123. data/lib/arel/nodes/unary.rb +1 -0
  124. data/lib/arel/nodes/values_list.rb +2 -17
  125. data/lib/arel/select_manager.rb +10 -10
  126. data/lib/arel/visitors/depth_first.rb +7 -2
  127. data/lib/arel/visitors/dot.rb +7 -2
  128. data/lib/arel/visitors/ibm_db.rb +13 -0
  129. data/lib/arel/visitors/informix.rb +6 -0
  130. data/lib/arel/visitors/mssql.rb +15 -1
  131. data/lib/arel/visitors/oracle12.rb +4 -5
  132. data/lib/arel/visitors/postgresql.rb +4 -10
  133. data/lib/arel/visitors/to_sql.rb +107 -131
  134. data/lib/arel/visitors/visitor.rb +9 -5
  135. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  136. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  137. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  138. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  139. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  140. metadata +16 -12
  141. data/lib/active_record/collection_cache_key.rb +0 -53
  142. data/lib/arel/nodes/values.rb +0 -16
@@ -2,18 +2,23 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Querying
5
- delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :none?, :one?, to: :all
6
- delegate :second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!, :forty_two, :forty_two!, :third_to_last, :third_to_last!, :second_to_last, :second_to_last!, to: :all
7
- delegate :first_or_create, :first_or_create!, :first_or_initialize, to: :all
8
- delegate :find_or_create_by, :find_or_create_by!, :create_or_find_by, :create_or_find_by!, :find_or_initialize_by, to: :all
9
- delegate :find_by, :find_by!, to: :all
10
- delegate :destroy_all, :delete_all, :update_all, :destroy_by, :delete_by, to: :all
11
- delegate :find_each, :find_in_batches, :in_batches, to: :all
12
- delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :left_joins, :left_outer_joins, :or,
13
- :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :extending,
14
- :having, :create_with, :distinct, :references, :none, :unscope, :merge, to: :all
15
- delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all
16
- delegate :pluck, :pick, :ids, to: :all
5
+ QUERYING_METHODS = [
6
+ :find, :find_by, :find_by!, :take, :take!, :first, :first!, :last, :last!,
7
+ :second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!,
8
+ :forty_two, :forty_two!, :third_to_last, :third_to_last!, :second_to_last, :second_to_last!,
9
+ :exists?, :any?, :many?, :none?, :one?,
10
+ :first_or_create, :first_or_create!, :first_or_initialize,
11
+ :find_or_create_by, :find_or_create_by!, :find_or_initialize_by,
12
+ :create_or_find_by, :create_or_find_by!,
13
+ :destroy_all, :delete_all, :update_all, :touch_all, :destroy_by, :delete_by,
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, :extending, :or,
17
+ :having, :create_with, :distinct, :references, :none, :unscope, :optimizer_hints, :merge, :except, :only,
18
+ :count, :average, :minimum, :maximum, :sum, :calculate, :annotate,
19
+ :pluck, :pick, :ids
20
+ ].freeze # :nodoc:
21
+ delegate(*QUERYING_METHODS, to: :all)
17
22
 
18
23
  # Executes a custom SQL query against your database and returns all the results. The results will
19
24
  # be returned as an array, with the requested columns encapsulated as attributes of the model you call
@@ -134,7 +134,6 @@ end_error
134
134
 
135
135
  cache = YAML.load(File.read(filename))
136
136
  if cache.version == current_version
137
- connection.schema_cache = cache
138
137
  connection_pool.schema_cache = cache.dup
139
138
  else
140
139
  warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{current_version}, but the one in the cache is #{cache.version}."
@@ -2,6 +2,8 @@
2
2
 
3
3
  require "active_record"
4
4
 
5
+ databases = ActiveRecord::Tasks::DatabaseTasks.setup_initial_database_yaml
6
+
5
7
  db_namespace = namespace :db do
6
8
  desc "Set the environment value for the database"
7
9
  task "environment:set" => :load_config do
@@ -23,7 +25,7 @@ db_namespace = namespace :db do
23
25
  ActiveRecord::Tasks::DatabaseTasks.create_all
24
26
  end
25
27
 
26
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
28
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
27
29
  desc "Create #{spec_name} database for current environment"
28
30
  task spec_name => :load_config do
29
31
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
@@ -42,7 +44,7 @@ db_namespace = namespace :db do
42
44
  ActiveRecord::Tasks::DatabaseTasks.drop_all
43
45
  end
44
46
 
45
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
47
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
46
48
  desc "Drop #{spec_name} database for current environment"
47
49
  task spec_name => [:load_config, :check_protected_environments] do
48
50
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
@@ -66,6 +68,11 @@ db_namespace = namespace :db do
66
68
  end
67
69
  end
68
70
 
71
+ # desc "Truncates tables of each database for current environment"
72
+ task truncate_all: [:load_config, :check_protected_environments] do
73
+ ActiveRecord::Tasks::DatabaseTasks.truncate_all
74
+ end
75
+
69
76
  # desc "Empty the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:purge:all to purge all databases in the config). Without RAILS_ENV it defaults to purging the development and test databases."
70
77
  task purge: [:load_config, :check_protected_environments] do
71
78
  ActiveRecord::Tasks::DatabaseTasks.purge_current
@@ -73,11 +80,14 @@ db_namespace = namespace :db do
73
80
 
74
81
  desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)."
75
82
  task migrate: :load_config do
76
- ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
83
+ original_config = ActiveRecord::Base.connection_config
84
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
77
85
  ActiveRecord::Base.establish_connection(db_config.config)
78
86
  ActiveRecord::Tasks::DatabaseTasks.migrate
79
87
  end
80
88
  db_namespace["_dump"].invoke
89
+ ensure
90
+ ActiveRecord::Base.establish_connection(original_config)
81
91
  end
82
92
 
83
93
  # IMPORTANT: This task won't dump the schema if ActiveRecord::Base.dump_schema_after_migration is set to false
@@ -96,7 +106,7 @@ db_namespace = namespace :db do
96
106
  end
97
107
 
98
108
  namespace :migrate do
99
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
109
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
100
110
  desc "Migrate #{spec_name} database for current environment"
101
111
  task spec_name => :load_config do
102
112
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
@@ -123,6 +133,8 @@ db_namespace = namespace :db do
123
133
 
124
134
  # desc 'Runs the "up" for a given migration VERSION.'
125
135
  task up: :load_config do
136
+ ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:up")
137
+
126
138
  raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
127
139
 
128
140
  ActiveRecord::Tasks::DatabaseTasks.check_target_version
@@ -134,8 +146,29 @@ db_namespace = namespace :db do
134
146
  db_namespace["_dump"].invoke
135
147
  end
136
148
 
149
+ namespace :up do
150
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
151
+ task spec_name => :load_config do
152
+ raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
153
+
154
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
155
+
156
+ ActiveRecord::Base.establish_connection(db_config.config)
157
+ ActiveRecord::Tasks::DatabaseTasks.check_target_version
158
+ ActiveRecord::Base.connection.migration_context.run(
159
+ :up,
160
+ ActiveRecord::Tasks::DatabaseTasks.target_version
161
+ )
162
+
163
+ db_namespace["_dump"].invoke
164
+ end
165
+ end
166
+ end
167
+
137
168
  # desc 'Runs the "down" for a given migration VERSION.'
138
169
  task down: :load_config do
170
+ ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:down")
171
+
139
172
  raise "VERSION is required - To go down one migration, use db:rollback" if !ENV["VERSION"] || ENV["VERSION"].empty?
140
173
 
141
174
  ActiveRecord::Tasks::DatabaseTasks.check_target_version
@@ -147,16 +180,35 @@ db_namespace = namespace :db do
147
180
  db_namespace["_dump"].invoke
148
181
  end
149
182
 
183
+ namespace :down do
184
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
185
+ task spec_name => :load_config do
186
+ raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
187
+
188
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
189
+
190
+ ActiveRecord::Base.establish_connection(db_config.config)
191
+ ActiveRecord::Tasks::DatabaseTasks.check_target_version
192
+ ActiveRecord::Base.connection.migration_context.run(
193
+ :down,
194
+ ActiveRecord::Tasks::DatabaseTasks.target_version
195
+ )
196
+
197
+ db_namespace["_dump"].invoke
198
+ end
199
+ end
200
+ end
201
+
150
202
  desc "Display status of migrations"
151
203
  task status: :load_config do
152
- ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
204
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
153
205
  ActiveRecord::Base.establish_connection(db_config.config)
154
206
  ActiveRecord::Tasks::DatabaseTasks.migrate_status
155
207
  end
156
208
  end
157
209
 
158
210
  namespace :status do
159
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
211
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
160
212
  desc "Display status of migrations for #{spec_name} database"
161
213
  task spec_name => :load_config do
162
214
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
@@ -203,7 +255,11 @@ db_namespace = namespace :db do
203
255
 
204
256
  # desc "Raises an error if there are pending migrations"
205
257
  task abort_if_pending_migrations: :load_config do
206
- pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
258
+ pending_migrations = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).flat_map do |db_config|
259
+ ActiveRecord::Base.establish_connection(db_config.config)
260
+
261
+ ActiveRecord::Base.connection.migration_context.open.pending_migrations
262
+ end
207
263
 
208
264
  if pending_migrations.any?
209
265
  puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
@@ -212,17 +268,74 @@ db_namespace = namespace :db do
212
268
  end
213
269
  abort %{Run `rails db:migrate` to update your database then try again.}
214
270
  end
271
+ ensure
272
+ ActiveRecord::Base.establish_connection(ActiveRecord::Tasks::DatabaseTasks.env.to_sym)
273
+ end
274
+
275
+ namespace :abort_if_pending_migrations do
276
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
277
+ # desc "Raises an error if there are pending migrations for #{spec_name} database"
278
+ task spec_name => :load_config do
279
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
280
+ ActiveRecord::Base.establish_connection(db_config.config)
281
+
282
+ pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
283
+
284
+ if pending_migrations.any?
285
+ puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
286
+ pending_migrations.each do |pending_migration|
287
+ puts " %4d %s" % [pending_migration.version, pending_migration.name]
288
+ end
289
+ abort %{Run `rails db:migrate:#{spec_name}` to update your database then try again.}
290
+ end
291
+ end
292
+ end
215
293
  end
216
294
 
217
295
  desc "Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)"
218
296
  task setup: ["db:schema:load_if_ruby", "db:structure:load_if_sql", :seed]
219
297
 
298
+ desc "Runs setup if database does not exist, or runs migrations if it does"
299
+ task prepare: :load_config do
300
+ seed = false
301
+
302
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
303
+ ActiveRecord::Base.establish_connection(db_config.config)
304
+
305
+ # Skipped when no database
306
+ ActiveRecord::Tasks::DatabaseTasks.migrate
307
+ if ActiveRecord::Base.dump_schema_after_migration
308
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, ActiveRecord::Base.schema_format, db_config.spec_name)
309
+ end
310
+
311
+ rescue ActiveRecord::NoDatabaseError
312
+ ActiveRecord::Tasks::DatabaseTasks.create_current(db_config.env_name, db_config.spec_name)
313
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(
314
+ db_config.config,
315
+ ActiveRecord::Base.schema_format,
316
+ nil,
317
+ db_config.env_name,
318
+ db_config.spec_name
319
+ )
320
+
321
+ seed = true
322
+ end
323
+
324
+ ActiveRecord::Base.establish_connection
325
+ ActiveRecord::Tasks::DatabaseTasks.load_seed if seed
326
+ end
327
+
220
328
  desc "Loads the seed data from db/seeds.rb"
221
329
  task seed: :load_config do
222
330
  db_namespace["abort_if_pending_migrations"].invoke
223
331
  ActiveRecord::Tasks::DatabaseTasks.load_seed
224
332
  end
225
333
 
334
+ namespace :seed do
335
+ desc "Truncates tables of each database for current environment and loads the seeds"
336
+ task replant: [:load_config, :truncate_all, :seed]
337
+ end
338
+
226
339
  namespace :fixtures do
227
340
  desc "Loads fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
228
341
  task load: :load_config do
@@ -274,13 +387,9 @@ db_namespace = namespace :db do
274
387
  namespace :schema do
275
388
  desc "Creates a db/schema.rb file that is portable against any DB supported by Active Record"
276
389
  task dump: :load_config do
277
- require "active_record/schema_dumper"
278
- ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
279
- filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(db_config.spec_name, :ruby)
280
- File.open(filename, "w:utf-8") do |file|
281
- ActiveRecord::Base.establish_connection(db_config.config)
282
- ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
283
- end
390
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
391
+ ActiveRecord::Base.establish_connection(db_config.config)
392
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :ruby, db_config.spec_name)
284
393
  end
285
394
 
286
395
  db_namespace["schema:dump"].reenable
@@ -298,7 +407,7 @@ db_namespace = namespace :db do
298
407
  namespace :cache do
299
408
  desc "Creates a db/schema_cache.yml file."
300
409
  task dump: :load_config do
301
- ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
410
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
302
411
  ActiveRecord::Base.establish_connection(db_config.config)
303
412
  filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(db_config.spec_name)
304
413
  ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(
@@ -310,7 +419,7 @@ db_namespace = namespace :db do
310
419
 
311
420
  desc "Clears a db/schema_cache.yml file."
312
421
  task clear: :load_config do
313
- ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
422
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
314
423
  filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(db_config.spec_name)
315
424
  rm_f filename, verbose: false
316
425
  end
@@ -321,16 +430,9 @@ db_namespace = namespace :db do
321
430
  namespace :structure do
322
431
  desc "Dumps the database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql"
323
432
  task dump: :load_config do
324
- ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
433
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
325
434
  ActiveRecord::Base.establish_connection(db_config.config)
326
- filename = ActiveRecord::Tasks::DatabaseTasks.dump_filename(db_config.spec_name, :sql)
327
- ActiveRecord::Tasks::DatabaseTasks.structure_dump(db_config.config, filename)
328
- if ActiveRecord::SchemaMigration.table_exists?
329
- File.open(filename, "a") do |f|
330
- f.puts ActiveRecord::Base.connection.dump_schema_information
331
- f.print "\n"
332
- end
333
- end
435
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :sql, db_config.spec_name)
334
436
  end
335
437
 
336
438
  db_namespace["structure:dump"].reenable
@@ -21,12 +21,12 @@ module ActiveRecord
21
21
 
22
22
  def add_reflection(ar, name, reflection)
23
23
  ar.clear_reflections_cache
24
- name = name.to_s
24
+ name = -name.to_s
25
25
  ar._reflections = ar._reflections.except(name).merge!(name => reflection)
26
26
  end
27
27
 
28
28
  def add_aggregate_reflection(ar, name, reflection)
29
- ar.aggregate_reflections = ar.aggregate_reflections.merge(name.to_s => reflection)
29
+ ar.aggregate_reflections = ar.aggregate_reflections.merge(-name.to_s => reflection)
30
30
  end
31
31
 
32
32
  private
@@ -477,7 +477,7 @@ module ActiveRecord
477
477
  def check_preloadable!
478
478
  return unless scope
479
479
 
480
- if scope.arity > 0
480
+ unless scope.arity == 0
481
481
  raise ArgumentError, <<-MSG.squish
482
482
  The association scope '#{name}' is instance dependent (the scope
483
483
  block takes an argument). Preloading instance dependent scopes is
@@ -5,7 +5,7 @@ module ActiveRecord
5
5
  class Relation
6
6
  MULTI_VALUE_METHODS = [:includes, :eager_load, :preload, :select, :group,
7
7
  :order, :joins, :left_outer_joins, :references,
8
- :extending, :unscope]
8
+ :extending, :unscope, :optimizer_hints, :annotate]
9
9
 
10
10
  SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :reordering,
11
11
  :reverse_order, :distinct, :create_with, :skip_query_cache]
@@ -197,6 +197,10 @@ module ActiveRecord
197
197
  # if a DELETE between those two statements is run by another client. But for most applications,
198
198
  # that's a significantly less likely condition to hit.
199
199
  # * It relies on exception handling to handle control flow, which may be marginally slower.
200
+ # * The primary key may auto-increment on each create, even if it fails. This can accelerate
201
+ # the problem of running out of integers, if the underlying table is still stuck on a primary
202
+ # key of type int (note: All Rails apps since 5.1+ have defaulted to bigint, which is not liable
203
+ # to this problem).
200
204
  #
201
205
  # This method will return a record if all given attributes are covered by unique constraints
202
206
  # (unless the INSERT -> DELETE -> SELECT race condition is triggered), but if creation was attempted
@@ -287,31 +291,99 @@ module ActiveRecord
287
291
  limit_value ? records.many? : size > 1
288
292
  end
289
293
 
290
- # Returns a cache key that can be used to identify the records fetched by
291
- # this query. The cache key is built with a fingerprint of the sql query,
292
- # the number of records matched by the query and a timestamp of the last
293
- # updated record. When a new record comes to match the query, or any of
294
- # the existing records is updated or deleted, the cache key changes.
294
+ # Returns a stable cache key that can be used to identify this query.
295
+ # The cache key is built with a fingerprint of the SQL query.
295
296
  #
296
- # Product.where("name like ?", "%Cosmic Encounter%").cache_key
297
- # # => "products/query-1850ab3d302391b85b8693e941286659-1-20150714212553907087000"
297
+ # Product.where("name like ?", "%Cosmic Encounter%").cache_key
298
+ # # => "products/query-1850ab3d302391b85b8693e941286659"
298
299
  #
299
- # If the collection is loaded, the method will iterate through the records
300
- # to generate the timestamp, otherwise it will trigger one SQL query like:
300
+ # If ActiveRecord::Base.collection_cache_versioning is turned off, as it was
301
+ # in Rails 6.0 and earlier, the cache key will also include a version.
301
302
  #
302
- # SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%')
303
+ # ActiveRecord::Base.collection_cache_versioning = false
304
+ # Product.where("name like ?", "%Cosmic Encounter%").cache_key
305
+ # # => "products/query-1850ab3d302391b85b8693e941286659-1-20150714212553907087000"
303
306
  #
304
307
  # You can also pass a custom timestamp column to fetch the timestamp of the
305
308
  # last updated record.
306
309
  #
307
310
  # Product.where("name like ?", "%Game%").cache_key(:last_reviewed_at)
308
- #
309
- # You can customize the strategy to generate the key on a per model basis
310
- # overriding ActiveRecord::Base#collection_cache_key.
311
311
  def cache_key(timestamp_column = :updated_at)
312
312
  @cache_keys ||= {}
313
- @cache_keys[timestamp_column] ||= @klass.collection_cache_key(self, timestamp_column)
313
+ @cache_keys[timestamp_column] ||= klass.collection_cache_key(self, timestamp_column)
314
+ end
315
+
316
+ def compute_cache_key(timestamp_column = :updated_at) # :nodoc:
317
+ query_signature = ActiveSupport::Digest.hexdigest(to_sql)
318
+ key = "#{klass.model_name.cache_key}/query-#{query_signature}"
319
+
320
+ if cache_version(timestamp_column)
321
+ key
322
+ else
323
+ "#{key}-#{compute_cache_version(timestamp_column)}"
324
+ end
325
+ end
326
+ private :compute_cache_key
327
+
328
+ # Returns a cache version that can be used together with the cache key to form
329
+ # a recyclable caching scheme. The cache version is built with the number of records
330
+ # matching the query, and the timestamp of the last updated record. When a new record
331
+ # comes to match the query, or any of the existing records is updated or deleted,
332
+ # the cache version changes.
333
+ #
334
+ # If the collection is loaded, the method will iterate through the records
335
+ # to generate the timestamp, otherwise it will trigger one SQL query like:
336
+ #
337
+ # SELECT COUNT(*), MAX("products"."updated_at") FROM "products" WHERE (name like '%Cosmic Encounter%')
338
+ def cache_version(timestamp_column = :updated_at)
339
+ if collection_cache_versioning
340
+ @cache_versions ||= {}
341
+ @cache_versions[timestamp_column] ||= compute_cache_version(timestamp_column)
342
+ end
343
+ end
344
+
345
+ def compute_cache_version(timestamp_column) # :nodoc:
346
+ if loaded? || distinct_value
347
+ size = records.size
348
+ if size > 0
349
+ timestamp = max_by(&timestamp_column)._read_attribute(timestamp_column)
350
+ end
351
+ else
352
+ collection = eager_loading? ? apply_join_dependency : self
353
+
354
+ column = connection.visitor.compile(arel_attribute(timestamp_column))
355
+ select_values = "COUNT(*) AS #{connection.quote_column_name("size")}, MAX(%s) AS timestamp"
356
+
357
+ if collection.has_limit_or_offset?
358
+ query = collection.select("#{column} AS collection_cache_key_timestamp")
359
+ subquery_alias = "subquery_for_cache_key"
360
+ subquery_column = "#{subquery_alias}.collection_cache_key_timestamp"
361
+ arel = query.build_subquery(subquery_alias, select_values % subquery_column)
362
+ else
363
+ query = collection.unscope(:order)
364
+ query.select_values = [select_values % column]
365
+ arel = query.arel
366
+ end
367
+
368
+ result = connection.select_one(arel, nil)
369
+
370
+ if result
371
+ column_type = klass.type_for_attribute(timestamp_column)
372
+ timestamp = column_type.deserialize(result["timestamp"])
373
+ size = result["size"]
374
+ else
375
+ timestamp = nil
376
+ size = 0
377
+ end
378
+ end
379
+
380
+ if timestamp
381
+ "#{size}-#{timestamp.utc.to_s(cache_timestamp_format)}"
382
+ else
383
+ "#{size}"
384
+ end
314
385
  end
386
+ private :compute_cache_version
315
387
 
316
388
  # Scope all queries to the current scope.
317
389
  #
@@ -338,6 +410,8 @@ module ActiveRecord
338
410
  # trigger Active Record callbacks or validations. However, values passed to #update_all will still go through
339
411
  # Active Record's normal type casting and serialization.
340
412
  #
413
+ # Note: As Active Record callbacks are not triggered, this method will not automatically update +updated_at+/+updated_on+ columns.
414
+ #
341
415
  # ==== Parameters
342
416
  #
343
417
  # * +updates+ - A string, array, or hash representing the SET part of an SQL statement.
@@ -412,10 +486,10 @@ module ActiveRecord
412
486
  update_all updates
413
487
  end
414
488
 
415
- # Touches all records in the current relation without instantiating records first with the updated_at/on attributes
489
+ # Touches all records in the current relation without instantiating records first with the +updated_at+/+updated_on+ attributes
416
490
  # set to the current time or the time specified.
417
491
  # This method can be passed attribute names and an optional time argument.
418
- # If attribute names are passed, they are updated along with updated_at/on attributes.
492
+ # If attribute names are passed, they are updated along with +updated_at+/+updated_on+ attributes.
419
493
  # If no time argument is passed, the current time is used as default.
420
494
  #
421
495
  # === Examples
@@ -479,8 +553,8 @@ module ActiveRecord
479
553
  # # => ActiveRecord::ActiveRecordError: delete_all doesn't support distinct
480
554
  def delete_all
481
555
  invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
482
- value = get_value(method)
483
- SINGLE_VALUE_METHODS.include?(method) ? value : value.any?
556
+ value = @values[method]
557
+ method == :distinct ? value : value&.any?
484
558
  end
485
559
  if invalid_methods.any?
486
560
  raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
@@ -555,6 +629,7 @@ module ActiveRecord
555
629
  @to_sql = @arel = @loaded = @should_eager_load = nil
556
630
  @records = [].freeze
557
631
  @offsets = {}
632
+ @take = nil
558
633
  self
559
634
  end
560
635
 
@@ -670,6 +745,10 @@ module ActiveRecord
670
745
  @loaded = true
671
746
  end
672
747
 
748
+ def null_relation? # :nodoc:
749
+ is_a?(NullRelation)
750
+ end
751
+
673
752
  private
674
753
  def already_in_scope?
675
754
  @delegate_to_klass && begin
@@ -719,7 +798,7 @@ module ActiveRecord
719
798
  @records =
720
799
  if eager_loading?
721
800
  apply_join_dependency do |relation, join_dependency|
722
- if ActiveRecord::NullRelation === relation
801
+ if relation.null_relation?
723
802
  []
724
803
  else
725
804
  relation = join_dependency.apply_column_aliases(relation)