activerecord 4.0.0.beta1 → 4.0.0.rc1

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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +573 -30
  3. data/README.rdoc +3 -3
  4. data/lib/active_record.rb +8 -2
  5. data/lib/active_record/associations.rb +16 -9
  6. data/lib/active_record/associations/association.rb +8 -6
  7. data/lib/active_record/associations/association_scope.rb +2 -1
  8. data/lib/active_record/associations/belongs_to_association.rb +2 -2
  9. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  10. data/lib/active_record/associations/builder/belongs_to.rb +37 -5
  11. data/lib/active_record/associations/collection_association.rb +38 -14
  12. data/lib/active_record/associations/collection_proxy.rb +18 -15
  13. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +3 -3
  14. data/lib/active_record/associations/has_many_association.rb +4 -3
  15. data/lib/active_record/associations/has_many_through_association.rb +1 -1
  16. data/lib/active_record/associations/has_one_association.rb +1 -1
  17. data/lib/active_record/associations/join_dependency.rb +29 -8
  18. data/lib/active_record/associations/join_dependency/join_association.rb +26 -6
  19. data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
  20. data/lib/active_record/associations/join_dependency/join_part.rb +6 -6
  21. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
  22. data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
  23. data/lib/active_record/associations/through_association.rb +1 -1
  24. data/lib/active_record/attribute_assignment.rb +5 -5
  25. data/lib/active_record/attribute_methods.rb +20 -5
  26. data/lib/active_record/attribute_methods/dirty.rb +5 -1
  27. data/lib/active_record/attribute_methods/primary_key.rb +1 -1
  28. data/lib/active_record/attribute_methods/serialization.rb +9 -2
  29. data/lib/active_record/autosave_association.rb +19 -5
  30. data/lib/active_record/base.rb +3 -3
  31. data/lib/active_record/callbacks.rb +1 -1
  32. data/lib/active_record/coders/yaml_column.rb +8 -13
  33. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +3 -9
  34. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -1
  35. data/lib/active_record/connection_adapters/abstract/database_statements.rb +2 -1
  36. data/lib/active_record/connection_adapters/abstract/quoting.rb +2 -8
  37. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +60 -61
  38. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +13 -2
  39. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +291 -153
  40. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -1
  41. data/lib/active_record/connection_adapters/abstract_adapter.rb +92 -1
  42. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +55 -29
  43. data/lib/active_record/connection_adapters/column.rb +4 -4
  44. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  45. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -3
  46. data/lib/active_record/connection_adapters/mysql_adapter.rb +5 -5
  47. data/lib/active_record/connection_adapters/postgresql/cast.rb +22 -2
  48. data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -6
  49. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -13
  50. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +50 -9
  51. data/lib/active_record/connection_adapters/postgresql_adapter.rb +53 -24
  52. data/lib/active_record/connection_adapters/schema_cache.rb +35 -7
  53. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -5
  54. data/lib/active_record/connection_handling.rb +7 -7
  55. data/lib/active_record/core.rb +43 -8
  56. data/lib/active_record/counter_cache.rb +2 -1
  57. data/lib/active_record/errors.rb +11 -10
  58. data/lib/active_record/explain.rb +9 -7
  59. data/lib/active_record/explain_registry.rb +30 -0
  60. data/lib/active_record/explain_subscriber.rb +3 -2
  61. data/lib/active_record/fixture_set/file.rb +1 -2
  62. data/lib/active_record/fixtures.rb +13 -7
  63. data/lib/active_record/inheritance.rb +12 -4
  64. data/lib/active_record/integration.rb +3 -3
  65. data/lib/active_record/locking/optimistic.rb +2 -2
  66. data/lib/active_record/log_subscriber.rb +2 -2
  67. data/lib/active_record/migration.rb +69 -21
  68. data/lib/active_record/model_schema.rb +1 -1
  69. data/lib/active_record/nested_attributes.rb +98 -46
  70. data/lib/active_record/persistence.rb +3 -3
  71. data/lib/active_record/querying.rb +1 -1
  72. data/lib/active_record/railtie.rb +18 -4
  73. data/lib/active_record/railties/console_sandbox.rb +3 -2
  74. data/lib/active_record/railties/controller_runtime.rb +2 -1
  75. data/lib/active_record/railties/databases.rake +38 -80
  76. data/lib/active_record/reflection.rb +36 -3
  77. data/lib/active_record/relation.rb +18 -8
  78. data/lib/active_record/relation/calculations.rb +10 -5
  79. data/lib/active_record/relation/delegation.rb +3 -5
  80. data/lib/active_record/relation/finder_methods.rb +27 -14
  81. data/lib/active_record/relation/merger.rb +30 -2
  82. data/lib/active_record/relation/predicate_builder.rb +1 -6
  83. data/lib/active_record/relation/query_methods.rb +113 -16
  84. data/lib/active_record/runtime_registry.rb +17 -0
  85. data/lib/active_record/schema_dumper.rb +5 -1
  86. data/lib/active_record/schema_migration.rb +8 -5
  87. data/lib/active_record/scoping.rb +56 -2
  88. data/lib/active_record/scoping/default.rb +12 -11
  89. data/lib/active_record/scoping/named.rb +7 -3
  90. data/lib/active_record/serialization.rb +1 -1
  91. data/lib/active_record/statement_cache.rb +26 -0
  92. data/lib/active_record/tasks/database_tasks.rb +55 -10
  93. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  94. data/lib/active_record/tasks/mysql_database_tasks.rb +7 -2
  95. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  96. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  97. data/lib/active_record/timestamp.rb +6 -0
  98. data/lib/active_record/transactions.rb +7 -3
  99. data/lib/active_record/validations.rb +1 -2
  100. data/lib/active_record/validations/uniqueness.rb +7 -3
  101. data/lib/active_record/version.rb +7 -6
  102. data/lib/rails/generators/active_record/migration/migration_generator.rb +9 -2
  103. data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
  104. data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
  105. data/lib/rails/generators/active_record/model/templates/model.rb +4 -1
  106. metadata +17 -12
  107. data/examples/associations.png +0 -0
@@ -51,7 +51,7 @@ module ActiveRecord
51
51
  # how this "single-table" inheritance mapping is implemented.
52
52
  def instantiate(record, column_types = {})
53
53
  klass = discriminate_class_for_record(record)
54
- column_types = klass.decorate_columns(column_types)
54
+ column_types = klass.decorate_columns(column_types.dup)
55
55
  klass.allocate.init_with('attributes' => record, 'column_types' => column_types)
56
56
  end
57
57
 
@@ -410,7 +410,7 @@ module ActiveRecord
410
410
  def relation_for_destroy
411
411
  pk = self.class.primary_key
412
412
  column = self.class.columns_hash[pk]
413
- substitute = connection.substitute_at(column, 0)
413
+ substitute = self.class.connection.substitute_at(column, 0)
414
414
 
415
415
  relation = self.class.unscoped.where(
416
416
  self.class.arel_table[pk].eq(substitute))
@@ -443,7 +443,7 @@ module ActiveRecord
443
443
  real_column = db_columns_with_values[i].first
444
444
  bind_attrs[column] = klass.connection.substitute_at(real_column, i)
445
445
  end
446
- stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.compile_update(bind_attrs)
446
+ stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id_was || id)).arel.compile_update(bind_attrs)
447
447
  klass.connection.update stmt, 'SQL', db_columns_with_values
448
448
  end
449
449
  end
@@ -8,7 +8,7 @@ module ActiveRecord
8
8
  delegate :find_each, :find_in_batches, :to => :all
9
9
  delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
10
10
  :where, :preload, :eager_load, :includes, :from, :lock, :readonly,
11
- :having, :create_with, :uniq, :references, :none, :to => :all
11
+ :having, :create_with, :uniq, :distinct, :references, :none, :unscope, :to => :all
12
12
  delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :ids, :to => :all
13
13
 
14
14
  # Executes a custom SQL query against your database and returns all the results. The results will
@@ -36,6 +36,20 @@ module ActiveRecord
36
36
 
37
37
  rake_tasks do
38
38
  require "active_record/base"
39
+
40
+ ActiveRecord::Tasks::DatabaseTasks.env = Rails.env
41
+ ActiveRecord::Tasks::DatabaseTasks.db_dir = Rails.application.config.paths["db"].first
42
+ ActiveRecord::Tasks::DatabaseTasks.seed_loader = Rails.application
43
+ ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration
44
+ ActiveRecord::Tasks::DatabaseTasks.migrations_paths = Rails.application.paths['db/migrate'].to_a
45
+ ActiveRecord::Tasks::DatabaseTasks.fixtures_path = File.join Rails.root, 'test', 'fixtures'
46
+
47
+ if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
48
+ if engine.paths['db/migrate'].existent
49
+ ActiveRecord::Tasks::DatabaseTasks.migrations_paths += engine.paths['db/migrate'].to_a
50
+ end
51
+ end
52
+
39
53
  load "active_record/railties/databases.rake"
40
54
  end
41
55
 
@@ -49,7 +63,7 @@ module ActiveRecord
49
63
  Rails.logger.extend ActiveSupport::Logger.broadcast console
50
64
  end
51
65
 
52
- runner do |app|
66
+ runner do
53
67
  require "active_record/base"
54
68
  end
55
69
 
@@ -64,7 +78,7 @@ module ActiveRecord
64
78
  ActiveSupport.on_load(:active_record) { self.logger ||= ::Rails.logger }
65
79
  end
66
80
 
67
- initializer "active_record.migration_error" do |app|
81
+ initializer "active_record.migration_error" do
68
82
  if config.active_record.delete(:migration_error) == :page_load
69
83
  config.app_middleware.insert_after "::ActionDispatch::Callbacks",
70
84
  "ActiveRecord::Migration::CheckPending"
@@ -152,13 +166,13 @@ module ActiveRecord
152
166
  # and then establishes the connection.
153
167
  initializer "active_record.initialize_database" do |app|
154
168
  ActiveSupport.on_load(:active_record) do
155
- self.configurations = app.config.database_configuration
169
+ self.configurations = app.config.database_configuration || {}
156
170
  establish_connection
157
171
  end
158
172
  end
159
173
 
160
174
  # Expose database runtime to controller for logging.
161
- initializer "active_record.log_runtime" do |app|
175
+ initializer "active_record.log_runtime" do
162
176
  require "active_record/railties/controller_runtime"
163
177
  ActiveSupport.on_load(:action_controller) do
164
178
  include ActiveRecord::Railties::ControllerRuntime
@@ -1,4 +1,5 @@
1
- ActiveRecord::Base.connection.begin_db_transaction
1
+ ActiveRecord::Base.connection.begin_transaction(joinable: false)
2
+
2
3
  at_exit do
3
- ActiveRecord::Base.connection.rollback_db_transaction
4
+ ActiveRecord::Base.connection.rollback_transaction
4
5
  end
@@ -21,9 +21,10 @@ module ActiveRecord
21
21
  def cleanup_view_runtime
22
22
  if ActiveRecord::Base.connected?
23
23
  db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
24
+ self.db_runtime = (db_runtime || 0) + db_rt_before_render
24
25
  runtime = super
25
26
  db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime
26
- self.db_runtime = db_rt_before_render + db_rt_after_render
27
+ self.db_runtime += db_rt_after_render
27
28
  runtime - db_rt_after_render
28
29
  else
29
30
  super
@@ -2,14 +2,8 @@ require 'active_record'
2
2
 
3
3
  db_namespace = namespace :db do
4
4
  task :load_config do
5
- ActiveRecord::Base.configurations = Rails.application.config.database_configuration
6
- ActiveRecord::Migrator.migrations_paths = Rails.application.paths['db/migrate'].to_a
7
-
8
- if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
9
- if engine.paths['db/migrate'].existent
10
- ActiveRecord::Migrator.migrations_paths += engine.paths['db/migrate'].to_a
11
- end
12
- end
5
+ ActiveRecord::Base.configurations = ActiveRecord::Tasks::DatabaseTasks.database_configuration || {}
6
+ ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
13
7
  end
14
8
 
15
9
  namespace :create do
@@ -156,7 +150,7 @@ db_namespace = namespace :db do
156
150
  begin
157
151
  puts ActiveRecord::Tasks::DatabaseTasks.collation_current
158
152
  rescue NoMethodError
159
- $stderr.puts 'Sorry, your database adapter is not supported yet, feel free to submit a patch'
153
+ $stderr.puts 'Sorry, your database adapter is not supported yet. Feel free to submit a patch.'
160
154
  end
161
155
  end
162
156
 
@@ -166,11 +160,11 @@ db_namespace = namespace :db do
166
160
  end
167
161
 
168
162
  # desc "Raises an error if there are pending migrations"
169
- task :abort_if_pending_migrations => [:environment, :load_config] do
163
+ task :abort_if_pending_migrations => :environment do
170
164
  pending_migrations = ActiveRecord::Migrator.open(ActiveRecord::Migrator.migrations_paths).pending_migrations
171
165
 
172
166
  if pending_migrations.any?
173
- puts "You have #{pending_migrations.size} pending migrations:"
167
+ puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
174
168
  pending_migrations.each do |pending_migration|
175
169
  puts ' %4d %s' % [pending_migration.version, pending_migration.name]
176
170
  end
@@ -184,7 +178,7 @@ db_namespace = namespace :db do
184
178
  desc 'Load the seed data from db/seeds.rb'
185
179
  task :seed do
186
180
  db_namespace['abort_if_pending_migrations'].invoke
187
- Rails.application.load_seed
181
+ ActiveRecord::Tasks::DatabaseTasks.load_seed
188
182
  end
189
183
 
190
184
  namespace :fixtures do
@@ -192,7 +186,15 @@ db_namespace = namespace :db do
192
186
  task :load => [:environment, :load_config] do
193
187
  require 'active_record/fixtures'
194
188
 
195
- base_dir = File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
189
+ base_dir = if ENV['FIXTURES_PATH']
190
+ STDERR.puts "Using FIXTURES_PATH env variable is deprecated, please use " +
191
+ "ActiveRecord::Tasks::DatabaseTasks.fixtures_path = '/path/to/fixtures' " +
192
+ "instead."
193
+ File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
194
+ else
195
+ ActiveRecord::Tasks::DatabaseTasks.fixtures_path
196
+ end
197
+
196
198
  fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact
197
199
 
198
200
  (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file|
@@ -209,7 +211,16 @@ db_namespace = namespace :db do
209
211
 
210
212
  puts %Q(The fixture ID for "#{label}" is #{ActiveRecord::FixtureSet.identify(label)}.) if label
211
213
 
212
- base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures')
214
+ base_dir = if ENV['FIXTURES_PATH']
215
+ STDERR.puts "Using FIXTURES_PATH env variable is deprecated, please use " +
216
+ "ActiveRecord::Tasks::DatabaseTasks.fixtures_path = '/path/to/fixtures' " +
217
+ "instead."
218
+ File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
219
+ else
220
+ ActiveRecord::Tasks::DatabaseTasks.fixtures_path
221
+ end
222
+
223
+
213
224
  Dir["#{base_dir}/**/*.yml"].each do |file|
214
225
  if data = YAML::load(ERB.new(IO.read(file)).result)
215
226
  data.keys.each do |key|
@@ -228,7 +239,7 @@ db_namespace = namespace :db do
228
239
  desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR'
229
240
  task :dump => [:environment, :load_config] do
230
241
  require 'active_record/schema_dumper'
231
- filename = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
242
+ filename = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb')
232
243
  File.open(filename, "w:utf-8") do |file|
233
244
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
234
245
  end
@@ -237,11 +248,11 @@ db_namespace = namespace :db do
237
248
 
238
249
  desc 'Load a schema.rb file into the database'
239
250
  task :load => [:environment, :load_config] do
240
- file = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
251
+ file = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb')
241
252
  if File.exists?(file)
242
253
  load(file)
243
254
  else
244
- abort %{#{file} doesn't exist yet. Run `rake db:migrate` to create it then try again. If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded}
255
+ abort %{#{file} doesn't exist yet. Run `rake db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.}
245
256
  end
246
257
  end
247
258
 
@@ -253,7 +264,7 @@ db_namespace = namespace :db do
253
264
  desc 'Create a db/schema_cache.dump file.'
254
265
  task :dump => [:environment, :load_config] do
255
266
  con = ActiveRecord::Base.connection
256
- filename = File.join(Rails.application.config.paths["db"].first, "schema_cache.dump")
267
+ filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump")
257
268
 
258
269
  con.schema_cache.clear!
259
270
  con.tables.each { |table| con.schema_cache.add(table) }
@@ -262,7 +273,7 @@ db_namespace = namespace :db do
262
273
 
263
274
  desc 'Clear a db/schema_cache.dump file.'
264
275
  task :clear => [:environment, :load_config] do
265
- filename = File.join(Rails.application.config.paths["db"].first, "schema_cache.dump")
276
+ filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump")
266
277
  FileUtils.rm(filename) if File.exists?(filename)
267
278
  end
268
279
  end
@@ -270,32 +281,11 @@ db_namespace = namespace :db do
270
281
  end
271
282
 
272
283
  namespace :structure do
273
- def set_firebird_env(config)
274
- ENV['ISC_USER'] = config['username'].to_s if config['username']
275
- ENV['ISC_PASSWORD'] = config['password'].to_s if config['password']
276
- end
277
-
278
- def firebird_db_string(config)
279
- FireRuby::Database.db_string_for(config.symbolize_keys)
280
- end
281
-
282
284
  desc 'Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql'
283
285
  task :dump => [:environment, :load_config] do
284
- filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
286
+ filename = ENV['DB_STRUCTURE'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
285
287
  current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
286
- case current_config['adapter']
287
- when 'oci', 'oracle'
288
- ActiveRecord::Base.establish_connection(current_config)
289
- File.open(filename, "w:utf-8") { |f| f << ActiveRecord::Base.connection.structure_dump }
290
- when 'sqlserver'
291
- `smoscript -s #{current_config['host']} -d #{current_config['database']} -u #{current_config['username']} -p #{current_config['password']} -f #{filename} -A -U`
292
- when "firebird"
293
- set_firebird_env(current_config)
294
- db_string = firebird_db_string(current_config)
295
- sh "isql -a #{db_string} > #{filename}"
296
- else
297
- ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
298
- end
288
+ ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
299
289
 
300
290
  if ActiveRecord::Base.connection.supports_migrations?
301
291
  File.open(filename, "a") do |f|
@@ -307,23 +297,9 @@ db_namespace = namespace :db do
307
297
 
308
298
  # desc "Recreate the databases from the structure.sql file"
309
299
  task :load => [:environment, :load_config] do
300
+ filename = ENV['DB_STRUCTURE'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
310
301
  current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
311
- filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
312
- case current_config['adapter']
313
- when 'sqlserver'
314
- `sqlcmd -S #{current_config['host']} -d #{current_config['database']} -U #{current_config['username']} -P #{current_config['password']} -i #{filename}`
315
- when 'oci', 'oracle'
316
- ActiveRecord::Base.establish_connection(current_config)
317
- IO.read(filename).split(";\n\n").each do |ddl|
318
- ActiveRecord::Base.connection.execute(ddl)
319
- end
320
- when 'firebird'
321
- set_firebird_env(current_config)
322
- db_string = firebird_db_string(current_config)
323
- sh "isql -i #{filename} #{db_string}"
324
- else
325
- ActiveRecord::Tasks::DatabaseTasks.structure_load(current_config, filename)
326
- end
302
+ ActiveRecord::Tasks::DatabaseTasks.structure_load(current_config, filename)
327
303
  end
328
304
 
329
305
  task :load_if_sql => ['db:create', :environment] do
@@ -378,29 +354,11 @@ db_namespace = namespace :db do
378
354
 
379
355
  # desc "Empty the test database"
380
356
  task :purge => [:environment, :load_config] do
381
- abcs = ActiveRecord::Base.configurations
382
- case abcs['test']['adapter']
383
- when 'sqlserver'
384
- test = abcs.deep_dup['test']
385
- test_database = test['database']
386
- test['database'] = 'master'
387
- ActiveRecord::Base.establish_connection(test)
388
- ActiveRecord::Base.connection.recreate_database!(test_database)
389
- when "oci", "oracle"
390
- ActiveRecord::Base.establish_connection(:test)
391
- ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
392
- ActiveRecord::Base.connection.execute(ddl)
393
- end
394
- when 'firebird'
395
- ActiveRecord::Base.establish_connection(:test)
396
- ActiveRecord::Base.connection.recreate_database!
397
- else
398
- ActiveRecord::Tasks::DatabaseTasks.purge abcs['test']
399
- end
357
+ ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations['test']
400
358
  end
401
359
 
402
360
  # desc 'Check for pending migrations and load the test schema'
403
- task :prepare => 'db:abort_if_pending_migrations' do
361
+ task :prepare do
404
362
  unless ActiveRecord::Base.configurations.blank?
405
363
  db_namespace['test:load'].invoke
406
364
  end
@@ -426,7 +384,7 @@ namespace :railties do
426
384
  puts "NOTE: Migration #{migration.basename} from #{name} has been skipped. Migration with the same name already exists."
427
385
  end
428
386
 
429
- on_copy = Proc.new do |name, migration, old_path|
387
+ on_copy = Proc.new do |name, migration|
430
388
  puts "Copied migration #{migration.basename} from #{name}"
431
389
  end
432
390
 
@@ -436,5 +394,5 @@ namespace :railties do
436
394
  end
437
395
  end
438
396
 
439
- task 'test:prepare' => 'db:test:prepare'
397
+ task 'test:prepare' => ['db:test:prepare', 'db:test:load', 'db:abort_if_pending_migrations']
440
398
 
@@ -75,8 +75,13 @@ module ActiveRecord
75
75
  end
76
76
  end
77
77
 
78
- # Abstract base class for AggregateReflection and AssociationReflection. Objects of
78
+ # Base class for AggregateReflection and AssociationReflection. Objects of
79
79
  # AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
80
+ #
81
+ # MacroReflection
82
+ # AggregateReflection
83
+ # AssociationReflection
84
+ # ThroughReflection
80
85
  class MacroReflection
81
86
  # Returns the name of the macro.
82
87
  #
@@ -401,6 +406,16 @@ module ActiveRecord
401
406
  # has_many :tags, through: :taggings
402
407
  # end
403
408
  #
409
+ # class Tagging < ActiveRecord::Base
410
+ # belongs_to :post
411
+ # belongs_to :tag
412
+ # end
413
+ #
414
+ # tags_reflection = Post.reflect_on_association(:tags)
415
+ #
416
+ # taggings_reflection = tags_reflection.source_reflection
417
+ # # => <ActiveRecord::Reflection::AssociationReflection: @macro=:belongs_to, @name=:tag, @active_record=Tagging, @plural_name="tags">
418
+ #
404
419
  def source_reflection
405
420
  @source_reflection ||= source_reflection_names.collect { |name| through_reflection.klass.reflect_on_association(name) }.compact.first
406
421
  end
@@ -426,6 +441,17 @@ module ActiveRecord
426
441
  # The chain is built by recursively calling #chain on the source reflection and the through
427
442
  # reflection. The base case for the recursion is a normal association, which just returns
428
443
  # [self] as its #chain.
444
+ #
445
+ # class Post < ActiveRecord::Base
446
+ # has_many :taggings
447
+ # has_many :tags, through: :taggings
448
+ # end
449
+ #
450
+ # tags_reflection = Post.reflect_on_association(:tags)
451
+ # tags_reflection.chain
452
+ # # => [<ActiveRecord::Reflection::ThroughReflection: @macro=:has_many, @name=:tags, @options={:through=>:taggings}, @active_record=Post>,
453
+ # <ActiveRecord::Reflection::AssociationReflection: @macro=:has_many, @name=:taggings, @options={}, @active_record=Post>]
454
+ #
429
455
  def chain
430
456
  @chain ||= begin
431
457
  chain = source_reflection.chain + through_reflection.chain
@@ -496,9 +522,16 @@ module ActiveRecord
496
522
  source_reflection.options[:primary_key] || primary_key(klass || self.klass)
497
523
  end
498
524
 
499
- # Gets an array of possible <tt>:through</tt> source reflection names:
525
+ # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
526
+ #
527
+ # class Post < ActiveRecord::Base
528
+ # has_many :taggings
529
+ # has_many :tags, through: :taggings
530
+ # end
500
531
  #
501
- # [:singularized, :pluralized]
532
+ # tags_reflection = Post.reflect_on_association(:tags)
533
+ # tags_reflection.source_reflection_names
534
+ # # => [:tag, :tags]
502
535
  #
503
536
  def source_reflection_names
504
537
  @source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }
@@ -10,14 +10,14 @@ module ActiveRecord
10
10
  :extending]
11
11
 
12
12
  SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
13
- :reverse_order, :uniq, :create_with]
13
+ :reverse_order, :distinct, :create_with, :uniq]
14
14
 
15
15
  VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
16
16
 
17
17
  include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
18
18
 
19
19
  attr_reader :table, :klass, :loaded
20
- attr_accessor :default_scoped
20
+ attr_accessor :default_scoped, :proxy_association
21
21
  alias :model :klass
22
22
  alias :loaded? :loaded
23
23
  alias :default_scoped? :default_scoped
@@ -188,8 +188,7 @@ module ActiveRecord
188
188
  # Please see further details in the
189
189
  # {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain].
190
190
  def explain
191
- _, queries = collecting_queries_for_explain { exec_queries }
192
- exec_explain(queries)
191
+ exec_explain(collecting_queries_for_explain { exec_queries })
193
192
  end
194
193
 
195
194
  # Converts relation objects to Array.
@@ -236,8 +235,9 @@ module ActiveRecord
236
235
  # Scope all queries to the current scope.
237
236
  #
238
237
  # Comment.where(post_id: 1).scoping do
239
- # Comment.first # SELECT * FROM comments WHERE post_id = 1
238
+ # Comment.first
240
239
  # end
240
+ # # => SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
241
241
  #
242
242
  # Please check unscoped if you want to remove all previous scopes (including
243
243
  # the default_scope) during the execution of a block.
@@ -506,6 +506,12 @@ module ActiveRecord
506
506
  includes_values & joins_values
507
507
  end
508
508
 
509
+ # +uniq+ and +uniq!+ are silently deprecated. +uniq_value+ delegates to +distinct_value+
510
+ # to maintain backwards compatibility. Use +distinct_value+ instead.
511
+ def uniq_value
512
+ distinct_value
513
+ end
514
+
509
515
  # Compares two relations for equality.
510
516
  def ==(other)
511
517
  case other
@@ -589,21 +595,25 @@ module ActiveRecord
589
595
 
590
596
  if (references_values - joined_tables).any?
591
597
  true
592
- elsif (string_tables - joined_tables).any?
598
+ elsif !ActiveRecord::Base.disable_implicit_join_references &&
599
+ (string_tables - joined_tables).any?
593
600
  ActiveSupport::Deprecation.warn(
594
601
  "It looks like you are eager loading table(s) (one of: #{string_tables.join(', ')}) " \
595
602
  "that are referenced in a string SQL snippet. For example: \n" \
596
603
  "\n" \
597
604
  " Post.includes(:comments).where(\"comments.title = 'foo'\")\n" \
598
605
  "\n" \
599
- "Currently, Active Record recognises the table in the string, and knows to JOIN the " \
606
+ "Currently, Active Record recognizes the table in the string, and knows to JOIN the " \
600
607
  "comments table to the query, rather than loading comments in a separate query. " \
601
608
  "However, doing this without writing a full-blown SQL parser is inherently flawed. " \
602
609
  "Since we don't want to write an SQL parser, we are removing this functionality. " \
603
610
  "From now on, you must explicitly tell Active Record when you are referencing a table " \
604
611
  "from a string:\n" \
605
612
  "\n" \
606
- " Post.includes(:comments).where(\"comments.title = 'foo'\").references(:comments)\n\n"
613
+ " Post.includes(:comments).where(\"comments.title = 'foo'\").references(:comments)\n" \
614
+ "\n" \
615
+ "If you don't rely on implicit join references you can disable the feature entirely " \
616
+ "by setting `config.active_record.disable_implicit_join_references = true`."
607
617
  )
608
618
  true
609
619
  else