activerecord 6.0.0.beta1 → 6.0.0

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 (156) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +455 -9
  3. data/README.rdoc +3 -1
  4. data/lib/active_record/associations/association.rb +18 -1
  5. data/lib/active_record/associations/builder/association.rb +14 -18
  6. data/lib/active_record/associations/builder/belongs_to.rb +5 -2
  7. data/lib/active_record/associations/builder/collection_association.rb +5 -15
  8. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -1
  9. data/lib/active_record/associations/builder/has_many.rb +2 -0
  10. data/lib/active_record/associations/builder/has_one.rb +35 -1
  11. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  12. data/lib/active_record/associations/collection_association.rb +5 -6
  13. data/lib/active_record/associations/collection_proxy.rb +13 -42
  14. data/lib/active_record/associations/has_many_association.rb +1 -9
  15. data/lib/active_record/associations/has_many_through_association.rb +4 -11
  16. data/lib/active_record/associations/join_dependency/join_association.rb +21 -7
  17. data/lib/active_record/associations/join_dependency.rb +10 -9
  18. data/lib/active_record/associations/preloader/association.rb +37 -34
  19. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  20. data/lib/active_record/associations/preloader.rb +11 -6
  21. data/lib/active_record/associations.rb +3 -2
  22. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  23. data/lib/active_record/attribute_methods/dirty.rb +47 -14
  24. data/lib/active_record/attribute_methods/primary_key.rb +7 -15
  25. data/lib/active_record/attribute_methods/query.rb +2 -3
  26. data/lib/active_record/attribute_methods/read.rb +3 -9
  27. data/lib/active_record/attribute_methods/write.rb +6 -12
  28. data/lib/active_record/attribute_methods.rb +3 -53
  29. data/lib/active_record/attributes.rb +13 -0
  30. data/lib/active_record/autosave_association.rb +15 -5
  31. data/lib/active_record/base.rb +0 -1
  32. data/lib/active_record/callbacks.rb +3 -3
  33. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +124 -23
  34. data/lib/active_record/connection_adapters/abstract/database_limits.rb +8 -4
  35. data/lib/active_record/connection_adapters/abstract/database_statements.rb +101 -70
  36. data/lib/active_record/connection_adapters/abstract/query_cache.rb +11 -5
  37. data/lib/active_record/connection_adapters/abstract/quoting.rb +63 -6
  38. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -2
  39. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +51 -40
  40. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -1
  41. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +95 -30
  42. data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
  43. data/lib/active_record/connection_adapters/abstract_adapter.rb +108 -39
  44. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +93 -134
  45. data/lib/active_record/connection_adapters/column.rb +17 -13
  46. data/lib/active_record/connection_adapters/connection_specification.rb +1 -1
  47. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +3 -3
  48. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -7
  49. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  50. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  51. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  52. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +66 -5
  53. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  54. data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -5
  55. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -30
  56. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +5 -1
  57. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  58. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  59. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  60. data/lib/active_record/connection_adapters/postgresql/quoting.rb +40 -3
  61. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
  62. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +98 -89
  63. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +47 -63
  64. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +23 -27
  65. data/lib/active_record/connection_adapters/postgresql_adapter.rb +91 -24
  66. data/lib/active_record/connection_adapters/schema_cache.rb +32 -14
  67. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  68. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  69. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +38 -2
  70. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +28 -2
  71. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +69 -118
  72. data/lib/active_record/connection_handling.rb +32 -16
  73. data/lib/active_record/core.rb +27 -20
  74. data/lib/active_record/database_configurations/hash_config.rb +11 -11
  75. data/lib/active_record/database_configurations/url_config.rb +21 -16
  76. data/lib/active_record/database_configurations.rb +99 -50
  77. data/lib/active_record/dynamic_matchers.rb +1 -1
  78. data/lib/active_record/enum.rb +15 -0
  79. data/lib/active_record/errors.rb +18 -13
  80. data/lib/active_record/fixtures.rb +11 -6
  81. data/lib/active_record/gem_version.rb +1 -1
  82. data/lib/active_record/inheritance.rb +1 -1
  83. data/lib/active_record/insert_all.rb +179 -0
  84. data/lib/active_record/integration.rb +13 -1
  85. data/lib/active_record/internal_metadata.rb +5 -1
  86. data/lib/active_record/locking/optimistic.rb +3 -4
  87. data/lib/active_record/log_subscriber.rb +1 -1
  88. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  89. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  90. data/lib/active_record/middleware/database_selector.rb +75 -0
  91. data/lib/active_record/migration/command_recorder.rb +28 -14
  92. data/lib/active_record/migration/compatibility.rb +72 -63
  93. data/lib/active_record/migration.rb +62 -44
  94. data/lib/active_record/persistence.rb +212 -19
  95. data/lib/active_record/querying.rb +18 -14
  96. data/lib/active_record/railtie.rb +9 -1
  97. data/lib/active_record/railties/collection_cache_association_loading.rb +3 -3
  98. data/lib/active_record/railties/databases.rake +124 -25
  99. data/lib/active_record/reflection.rb +18 -32
  100. data/lib/active_record/relation/calculations.rb +40 -44
  101. data/lib/active_record/relation/delegation.rb +23 -31
  102. data/lib/active_record/relation/finder_methods.rb +13 -13
  103. data/lib/active_record/relation/merger.rb +11 -16
  104. data/lib/active_record/relation/query_attribute.rb +5 -3
  105. data/lib/active_record/relation/query_methods.rb +217 -68
  106. data/lib/active_record/relation/spawn_methods.rb +1 -1
  107. data/lib/active_record/relation/where_clause.rb +10 -10
  108. data/lib/active_record/relation.rb +184 -35
  109. data/lib/active_record/sanitization.rb +33 -4
  110. data/lib/active_record/schema.rb +1 -1
  111. data/lib/active_record/schema_dumper.rb +10 -1
  112. data/lib/active_record/schema_migration.rb +1 -1
  113. data/lib/active_record/scoping/default.rb +7 -15
  114. data/lib/active_record/scoping/named.rb +10 -2
  115. data/lib/active_record/scoping.rb +6 -7
  116. data/lib/active_record/statement_cache.rb +2 -2
  117. data/lib/active_record/store.rb +48 -0
  118. data/lib/active_record/table_metadata.rb +9 -13
  119. data/lib/active_record/tasks/database_tasks.rb +109 -6
  120. data/lib/active_record/tasks/mysql_database_tasks.rb +3 -1
  121. data/lib/active_record/test_databases.rb +1 -16
  122. data/lib/active_record/test_fixtures.rb +2 -2
  123. data/lib/active_record/timestamp.rb +35 -19
  124. data/lib/active_record/touch_later.rb +4 -2
  125. data/lib/active_record/transactions.rb +55 -45
  126. data/lib/active_record/type_caster/connection.rb +16 -10
  127. data/lib/active_record/validations/uniqueness.rb +4 -4
  128. data/lib/active_record/validations.rb +1 -0
  129. data/lib/active_record.rb +7 -1
  130. data/lib/arel/insert_manager.rb +3 -3
  131. data/lib/arel/nodes/and.rb +1 -1
  132. data/lib/arel/nodes/case.rb +1 -1
  133. data/lib/arel/nodes/comment.rb +29 -0
  134. data/lib/arel/nodes/select_core.rb +16 -12
  135. data/lib/arel/nodes/unary.rb +1 -0
  136. data/lib/arel/nodes/values_list.rb +2 -17
  137. data/lib/arel/nodes.rb +2 -1
  138. data/lib/arel/select_manager.rb +10 -10
  139. data/lib/arel/visitors/depth_first.rb +7 -2
  140. data/lib/arel/visitors/dot.rb +7 -2
  141. data/lib/arel/visitors/ibm_db.rb +13 -0
  142. data/lib/arel/visitors/informix.rb +6 -0
  143. data/lib/arel/visitors/mssql.rb +15 -1
  144. data/lib/arel/visitors/oracle12.rb +4 -5
  145. data/lib/arel/visitors/postgresql.rb +4 -10
  146. data/lib/arel/visitors/to_sql.rb +107 -131
  147. data/lib/arel/visitors/visitor.rb +9 -5
  148. data/lib/arel.rb +7 -0
  149. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  150. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  151. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  152. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  153. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  154. metadata +17 -13
  155. data/lib/active_record/collection_cache_key.rb +0 -53
  156. 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, 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
@@ -40,8 +45,7 @@ module ActiveRecord
40
45
  def find_by_sql(sql, binds = [], preparable: nil, &block)
41
46
  result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
42
47
  column_types = result_set.column_types.dup
43
- cached_columns_hash = connection.schema_cache.columns_hash(table_name)
44
- cached_columns_hash.each_key { |k| column_types.delete k }
48
+ attribute_types.each_key { |k| column_types.delete k }
45
49
  message_bus = ActiveSupport::Notifications.instrumenter
46
50
 
47
51
  payload = {
@@ -88,6 +88,14 @@ module ActiveRecord
88
88
  end
89
89
  end
90
90
 
91
+ initializer "active_record.database_selector" do
92
+ if options = config.active_record.delete(:database_selector)
93
+ resolver = config.active_record.delete(:database_resolver)
94
+ operations = config.active_record.delete(:database_resolver_context)
95
+ config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options
96
+ end
97
+ end
98
+
91
99
  initializer "Check for cache versioning support" do
92
100
  config.after_initialize do |app|
93
101
  ActiveSupport.on_load(:active_record) do
@@ -126,7 +134,6 @@ end_error
126
134
 
127
135
  cache = YAML.load(File.read(filename))
128
136
  if cache.version == current_version
129
- connection.schema_cache = cache
130
137
  connection_pool.schema_cache = cache.dup
131
138
  else
132
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}."
@@ -189,6 +196,7 @@ end_error
189
196
  # and then establishes the connection.
190
197
  initializer "active_record.initialize_database" do
191
198
  ActiveSupport.on_load(:active_record) do
199
+ self.connection_handlers = { writing_role => ActiveRecord::Base.default_connection_handler }
192
200
  self.configurations = Rails.application.config.database_configuration
193
201
  establish_connection
194
202
  end
@@ -3,7 +3,7 @@
3
3
  module ActiveRecord
4
4
  module Railties # :nodoc:
5
5
  module CollectionCacheAssociationLoading #:nodoc:
6
- def setup(context, options, block)
6
+ def setup(context, options, as, block)
7
7
  @relation = relation_from_options(options)
8
8
 
9
9
  super
@@ -20,12 +20,12 @@ module ActiveRecord
20
20
  end
21
21
  end
22
22
 
23
- def collection_without_template
23
+ def collection_without_template(*)
24
24
  @relation.preload_associations(@collection) if @relation
25
25
  super
26
26
  end
27
27
 
28
- def collection_with_template
28
+ def collection_with_template(*)
29
29
  @relation.preload_associations(@collection) if @relation
30
30
  super
31
31
  end
@@ -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,7 +80,7 @@ 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
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
77
84
  ActiveRecord::Base.establish_connection(db_config.config)
78
85
  ActiveRecord::Tasks::DatabaseTasks.migrate
79
86
  end
@@ -96,7 +103,7 @@ db_namespace = namespace :db do
96
103
  end
97
104
 
98
105
  namespace :migrate do
99
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
106
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
100
107
  desc "Migrate #{spec_name} database for current environment"
101
108
  task spec_name => :load_config do
102
109
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
@@ -123,6 +130,8 @@ db_namespace = namespace :db do
123
130
 
124
131
  # desc 'Runs the "up" for a given migration VERSION.'
125
132
  task up: :load_config do
133
+ ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:up")
134
+
126
135
  raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
127
136
 
128
137
  ActiveRecord::Tasks::DatabaseTasks.check_target_version
@@ -134,8 +143,29 @@ db_namespace = namespace :db do
134
143
  db_namespace["_dump"].invoke
135
144
  end
136
145
 
146
+ namespace :up do
147
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
148
+ task spec_name => :load_config do
149
+ raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
150
+
151
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
152
+
153
+ ActiveRecord::Base.establish_connection(db_config.config)
154
+ ActiveRecord::Tasks::DatabaseTasks.check_target_version
155
+ ActiveRecord::Base.connection.migration_context.run(
156
+ :up,
157
+ ActiveRecord::Tasks::DatabaseTasks.target_version
158
+ )
159
+
160
+ db_namespace["_dump"].invoke
161
+ end
162
+ end
163
+ end
164
+
137
165
  # desc 'Runs the "down" for a given migration VERSION.'
138
166
  task down: :load_config do
167
+ ActiveRecord::Tasks::DatabaseTasks.raise_for_multi_db(command: "db:migrate:down")
168
+
139
169
  raise "VERSION is required - To go down one migration, use db:rollback" if !ENV["VERSION"] || ENV["VERSION"].empty?
140
170
 
141
171
  ActiveRecord::Tasks::DatabaseTasks.check_target_version
@@ -147,16 +177,35 @@ db_namespace = namespace :db do
147
177
  db_namespace["_dump"].invoke
148
178
  end
149
179
 
180
+ namespace :down do
181
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
182
+ task spec_name => :load_config do
183
+ raise "VERSION is required" if !ENV["VERSION"] || ENV["VERSION"].empty?
184
+
185
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
186
+
187
+ ActiveRecord::Base.establish_connection(db_config.config)
188
+ ActiveRecord::Tasks::DatabaseTasks.check_target_version
189
+ ActiveRecord::Base.connection.migration_context.run(
190
+ :down,
191
+ ActiveRecord::Tasks::DatabaseTasks.target_version
192
+ )
193
+
194
+ db_namespace["_dump"].invoke
195
+ end
196
+ end
197
+ end
198
+
150
199
  desc "Display status of migrations"
151
200
  task status: :load_config do
152
- ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
201
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
153
202
  ActiveRecord::Base.establish_connection(db_config.config)
154
203
  ActiveRecord::Tasks::DatabaseTasks.migrate_status
155
204
  end
156
205
  end
157
206
 
158
207
  namespace :status do
159
- ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
208
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
160
209
  desc "Display status of migrations for #{spec_name} database"
161
210
  task spec_name => :load_config do
162
211
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
@@ -203,7 +252,11 @@ db_namespace = namespace :db do
203
252
 
204
253
  # desc "Raises an error if there are pending migrations"
205
254
  task abort_if_pending_migrations: :load_config do
206
- pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
255
+ pending_migrations = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).flat_map do |db_config|
256
+ ActiveRecord::Base.establish_connection(db_config.config)
257
+
258
+ ActiveRecord::Base.connection.migration_context.open.pending_migrations
259
+ end
207
260
 
208
261
  if pending_migrations.any?
209
262
  puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
@@ -212,17 +265,74 @@ db_namespace = namespace :db do
212
265
  end
213
266
  abort %{Run `rails db:migrate` to update your database then try again.}
214
267
  end
268
+ ensure
269
+ ActiveRecord::Base.establish_connection(ActiveRecord::Tasks::DatabaseTasks.env.to_sym)
270
+ end
271
+
272
+ namespace :abort_if_pending_migrations do
273
+ ActiveRecord::Tasks::DatabaseTasks.for_each(databases) do |spec_name|
274
+ # desc "Raises an error if there are pending migrations for #{spec_name} database"
275
+ task spec_name => :load_config do
276
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env, spec_name: spec_name)
277
+ ActiveRecord::Base.establish_connection(db_config.config)
278
+
279
+ pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
280
+
281
+ if pending_migrations.any?
282
+ puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
283
+ pending_migrations.each do |pending_migration|
284
+ puts " %4d %s" % [pending_migration.version, pending_migration.name]
285
+ end
286
+ abort %{Run `rails db:migrate:#{spec_name}` to update your database then try again.}
287
+ end
288
+ end
289
+ end
215
290
  end
216
291
 
217
292
  desc "Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)"
218
293
  task setup: ["db:schema:load_if_ruby", "db:structure:load_if_sql", :seed]
219
294
 
295
+ desc "Runs setup if database does not exist, or runs migrations if it does"
296
+ task prepare: :load_config do
297
+ seed = false
298
+
299
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
300
+ ActiveRecord::Base.establish_connection(db_config.config)
301
+
302
+ # Skipped when no database
303
+ ActiveRecord::Tasks::DatabaseTasks.migrate
304
+ if ActiveRecord::Base.dump_schema_after_migration
305
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, ActiveRecord::Base.schema_format, db_config.spec_name)
306
+ end
307
+
308
+ rescue ActiveRecord::NoDatabaseError
309
+ ActiveRecord::Tasks::DatabaseTasks.create_current(db_config.env_name, db_config.spec_name)
310
+ ActiveRecord::Tasks::DatabaseTasks.load_schema(
311
+ db_config.config,
312
+ ActiveRecord::Base.schema_format,
313
+ nil,
314
+ db_config.env_name,
315
+ db_config.spec_name
316
+ )
317
+
318
+ seed = true
319
+ end
320
+
321
+ ActiveRecord::Base.establish_connection
322
+ ActiveRecord::Tasks::DatabaseTasks.load_seed if seed
323
+ end
324
+
220
325
  desc "Loads the seed data from db/seeds.rb"
221
326
  task seed: :load_config do
222
327
  db_namespace["abort_if_pending_migrations"].invoke
223
328
  ActiveRecord::Tasks::DatabaseTasks.load_seed
224
329
  end
225
330
 
331
+ namespace :seed do
332
+ desc "Truncates tables of each database for current environment and loads the seeds"
333
+ task replant: [:load_config, :truncate_all, :seed]
334
+ end
335
+
226
336
  namespace :fixtures do
227
337
  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
338
  task load: :load_config do
@@ -274,13 +384,9 @@ db_namespace = namespace :db do
274
384
  namespace :schema do
275
385
  desc "Creates a db/schema.rb file that is portable against any DB supported by Active Record"
276
386
  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
387
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
388
+ ActiveRecord::Base.establish_connection(db_config.config)
389
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :ruby, db_config.spec_name)
284
390
  end
285
391
 
286
392
  db_namespace["schema:dump"].reenable
@@ -298,7 +404,7 @@ db_namespace = namespace :db do
298
404
  namespace :cache do
299
405
  desc "Creates a db/schema_cache.yml file."
300
406
  task dump: :load_config do
301
- ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
407
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
302
408
  ActiveRecord::Base.establish_connection(db_config.config)
303
409
  filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(db_config.spec_name)
304
410
  ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(
@@ -310,7 +416,7 @@ db_namespace = namespace :db do
310
416
 
311
417
  desc "Clears a db/schema_cache.yml file."
312
418
  task clear: :load_config do
313
- ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
419
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
314
420
  filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(db_config.spec_name)
315
421
  rm_f filename, verbose: false
316
422
  end
@@ -321,16 +427,9 @@ db_namespace = namespace :db do
321
427
  namespace :structure do
322
428
  desc "Dumps the database structure to db/structure.sql. Specify another file with SCHEMA=db/my_structure.sql"
323
429
  task dump: :load_config do
324
- ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).each do |db_config|
430
+ ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env).each do |db_config|
325
431
  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
432
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(db_config.config, :sql, db_config.spec_name)
334
433
  end
335
434
 
336
435
  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
@@ -178,28 +178,24 @@ module ActiveRecord
178
178
  scope ? [scope] : []
179
179
  end
180
180
 
181
- def build_join_constraint(table, foreign_table)
182
- key = join_keys.key
183
- foreign_key = join_keys.foreign_key
184
-
185
- constraint = table[key].eq(foreign_table[foreign_key])
186
-
187
- if klass.finder_needs_type_condition?
188
- table.create_and([constraint, klass.send(:type_condition, table)])
189
- else
190
- constraint
191
- end
192
- end
193
-
194
- def join_scope(table, foreign_klass)
181
+ def join_scope(table, foreign_table, foreign_klass)
195
182
  predicate_builder = predicate_builder(table)
196
183
  scope_chain_items = join_scopes(table, predicate_builder)
197
184
  klass_scope = klass_join_scope(table, predicate_builder)
198
185
 
186
+ key = join_keys.key
187
+ foreign_key = join_keys.foreign_key
188
+
189
+ klass_scope.where!(table[key].eq(foreign_table[foreign_key]))
190
+
199
191
  if type
200
192
  klass_scope.where!(type => foreign_klass.polymorphic_name)
201
193
  end
202
194
 
195
+ if klass.finder_needs_type_condition?
196
+ klass_scope.where!(klass.send(:type_condition, table))
197
+ end
198
+
203
199
  scope_chain_items.inject(klass_scope, &:merge!)
204
200
  end
205
201
 
@@ -481,7 +477,7 @@ module ActiveRecord
481
477
  def check_preloadable!
482
478
  return unless scope
483
479
 
484
- if scope.arity > 0
480
+ unless scope.arity == 0
485
481
  raise ArgumentError, <<-MSG.squish
486
482
  The association scope '#{name}' is instance dependent (the scope
487
483
  block takes an argument). Preloading instance dependent scopes is
@@ -612,21 +608,9 @@ module ActiveRecord
612
608
 
613
609
  # returns either +nil+ or the inverse association name that it finds.
614
610
  def automatic_inverse_of
615
- return unless can_find_inverse_of_automatically?(self)
611
+ if can_find_inverse_of_automatically?(self)
612
+ inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym
616
613
 
617
- inverse_name_candidates =
618
- if options[:as]
619
- [options[:as]]
620
- else
621
- active_record_name = active_record.name.demodulize
622
- [active_record_name, ActiveSupport::Inflector.pluralize(active_record_name)]
623
- end
624
-
625
- inverse_name_candidates.map! do |candidate|
626
- ActiveSupport::Inflector.underscore(candidate).to_sym
627
- end
628
-
629
- inverse_name_candidates.detect do |inverse_name|
630
614
  begin
631
615
  reflection = klass._reflect_on_association(inverse_name)
632
616
  rescue NameError
@@ -635,7 +619,9 @@ module ActiveRecord
635
619
  reflection = false
636
620
  end
637
621
 
638
- valid_inverse_reflection?(reflection)
622
+ if valid_inverse_reflection?(reflection)
623
+ return inverse_name
624
+ end
639
625
  end
640
626
  end
641
627
 
@@ -129,11 +129,12 @@ module ActiveRecord
129
129
  relation = apply_join_dependency
130
130
 
131
131
  if operation.to_s.downcase == "count"
132
- relation.distinct!
133
- # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
134
- if (column_name == :all || column_name.nil?) && select_values.empty?
135
- relation.order_values = []
132
+ unless distinct_value || distinct_select?(column_name || select_for_count)
133
+ relation.distinct!
134
+ relation.select_values = [ klass.primary_key || table[Arel.star] ]
136
135
  end
136
+ # PostgreSQL: ORDER BY expressions must appear in SELECT list when using DISTINCT
137
+ relation.order_values = []
137
138
  end
138
139
 
139
140
  relation.calculate(operation, column_name)
@@ -186,11 +187,9 @@ module ActiveRecord
186
187
  relation = apply_join_dependency
187
188
  relation.pluck(*column_names)
188
189
  else
189
- disallow_raw_sql!(column_names)
190
+ klass.disallow_raw_sql!(column_names)
190
191
  relation = spawn
191
- relation.select_values = column_names.map { |cn|
192
- @klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
193
- }
192
+ relation.select_values = column_names
194
193
  result = skip_query_cache_if_necessary { klass.connection.select_all(relation.arel, nil) }
195
194
  result.cast_values(klass.attribute_types)
196
195
  end
@@ -223,7 +222,6 @@ module ActiveRecord
223
222
  end
224
223
 
225
224
  private
226
-
227
225
  def has_include?(column_name)
228
226
  eager_loading? || (includes_values.present? && column_name && column_name != :all)
229
227
  end
@@ -238,10 +236,12 @@ module ActiveRecord
238
236
  if operation == "count"
239
237
  column_name ||= select_for_count
240
238
  if column_name == :all
241
- if distinct && (group_values.any? || select_values.empty? && order_values.empty?)
239
+ if !distinct
240
+ distinct = distinct_select?(select_for_count) if group_values.empty?
241
+ elsif group_values.any? || select_values.empty? && order_values.empty?
242
242
  column_name = primary_key
243
243
  end
244
- elsif column_name.is_a?(::String) && /\bDISTINCT[\s(]/i.match?(column_name)
244
+ elsif distinct_select?(column_name)
245
245
  distinct = nil
246
246
  end
247
247
  end
@@ -253,13 +253,15 @@ module ActiveRecord
253
253
  end
254
254
  end
255
255
 
256
+ def distinct_select?(column_name)
257
+ column_name.is_a?(::String) && /\bDISTINCT[\s(]/i.match?(column_name)
258
+ end
259
+
256
260
  def aggregate_column(column_name)
257
261
  return column_name if Arel::Expressions === column_name
258
262
 
259
- if @klass.has_attribute?(column_name) || @klass.attribute_alias?(column_name)
260
- @klass.arel_attribute(column_name)
261
- else
262
- Arel.sql(column_name == :all ? "*" : column_name.to_s)
263
+ arel_column(column_name.to_s) do |name|
264
+ Arel.sql(column_name == :all ? "*" : name)
263
265
  end
264
266
  end
265
267
 
@@ -304,25 +306,22 @@ module ActiveRecord
304
306
  end
305
307
 
306
308
  def execute_grouped_calculation(operation, column_name, distinct) #:nodoc:
307
- group_attrs = group_values
309
+ group_fields = group_values
308
310
 
309
- if group_attrs.first.respond_to?(:to_sym)
310
- association = @klass._reflect_on_association(group_attrs.first)
311
- associated = group_attrs.size == 1 && association && association.belongs_to? # only count belongs_to associations
312
- group_fields = Array(associated ? association.foreign_key : group_attrs)
313
- else
314
- group_fields = group_attrs
311
+ if group_fields.size == 1 && group_fields.first.respond_to?(:to_sym)
312
+ association = klass._reflect_on_association(group_fields.first)
313
+ associated = association && association.belongs_to? # only count belongs_to associations
314
+ group_fields = Array(association.foreign_key) if associated
315
315
  end
316
316
  group_fields = arel_columns(group_fields)
317
317
 
318
- group_aliases = group_fields.map { |field| column_alias_for(field) }
318
+ group_aliases = group_fields.map { |field|
319
+ field = connection.visitor.compile(field) if Arel.arel_node?(field)
320
+ column_alias_for(field.to_s.downcase)
321
+ }
319
322
  group_columns = group_aliases.zip(group_fields)
320
323
 
321
- if operation == "count" && column_name == :all
322
- aggregate_alias = "count_all"
323
- else
324
- aggregate_alias = column_alias_for([operation, column_name].join(" "))
325
- end
324
+ aggregate_alias = column_alias_for("#{operation} #{column_name.to_s.downcase}")
326
325
 
327
326
  select_values = [
328
327
  operation_over_aggregate_column(
@@ -367,25 +366,21 @@ module ActiveRecord
367
366
  end]
368
367
  end
369
368
 
370
- # Converts the given keys to the value that the database adapter returns as
369
+ # Converts the given field to the value that the database adapter returns as
371
370
  # a usable column name:
372
371
  #
373
372
  # column_alias_for("users.id") # => "users_id"
374
373
  # column_alias_for("sum(id)") # => "sum_id"
375
374
  # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
376
375
  # column_alias_for("count(*)") # => "count_all"
377
- def column_alias_for(keys)
378
- if keys.respond_to? :name
379
- keys = "#{keys.relation.name}.#{keys.name}"
380
- end
381
-
382
- table_name = keys.to_s.downcase
383
- table_name.gsub!(/\*/, "all")
384
- table_name.gsub!(/\W+/, " ")
385
- table_name.strip!
386
- table_name.gsub!(/ +/, "_")
387
-
388
- @klass.connection.table_alias_for(table_name)
376
+ def column_alias_for(field)
377
+ column_alias = +field
378
+ column_alias.gsub!(/\*/, "all")
379
+ column_alias.gsub!(/\W+/, " ")
380
+ column_alias.strip!
381
+ column_alias.gsub!(/ +/, "_")
382
+
383
+ connection.table_alias_for(column_alias)
389
384
  end
390
385
 
391
386
  def type_for(field, &block)
@@ -413,16 +408,17 @@ module ActiveRecord
413
408
 
414
409
  def build_count_subquery(relation, column_name, distinct)
415
410
  if column_name == :all
411
+ column_alias = Arel.star
416
412
  relation.select_values = [ Arel.sql(FinderMethods::ONE_AS_ONE) ] unless distinct
417
413
  else
418
414
  column_alias = Arel.sql("count_column")
419
415
  relation.select_values = [ aggregate_column(column_name).as(column_alias) ]
420
416
  end
421
417
 
422
- subquery = relation.arel.as(Arel.sql("subquery_for_count"))
423
- select_value = operation_over_aggregate_column(column_alias || Arel.star, "count", false)
418
+ subquery_alias = Arel.sql("subquery_for_count")
419
+ select_value = operation_over_aggregate_column(column_alias, "count", false)
424
420
 
425
- Arel::SelectManager.new(subquery).project(select_value)
421
+ relation.build_subquery(subquery_alias, select_value)
426
422
  end
427
423
  end
428
424
  end