activerecord 3.1.11 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. data/CHANGELOG.md +6294 -97
  2. data/README.rdoc +2 -2
  3. data/examples/performance.rb +55 -31
  4. data/lib/active_record/aggregations.rb +2 -2
  5. data/lib/active_record/associations/association.rb +2 -42
  6. data/lib/active_record/associations/association_scope.rb +3 -30
  7. data/lib/active_record/associations/builder/association.rb +6 -4
  8. data/lib/active_record/associations/builder/belongs_to.rb +3 -3
  9. data/lib/active_record/associations/builder/collection_association.rb +2 -2
  10. data/lib/active_record/associations/builder/has_many.rb +4 -4
  11. data/lib/active_record/associations/builder/has_one.rb +5 -6
  12. data/lib/active_record/associations/builder/singular_association.rb +3 -16
  13. data/lib/active_record/associations/collection_association.rb +55 -28
  14. data/lib/active_record/associations/collection_proxy.rb +1 -35
  15. data/lib/active_record/associations/has_many_association.rb +5 -1
  16. data/lib/active_record/associations/has_many_through_association.rb +11 -8
  17. data/lib/active_record/associations/join_dependency.rb +1 -1
  18. data/lib/active_record/associations/preloader/association.rb +3 -1
  19. data/lib/active_record/associations.rb +82 -69
  20. data/lib/active_record/attribute_assignment.rb +221 -0
  21. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  22. data/lib/active_record/attribute_methods/dirty.rb +3 -3
  23. data/lib/active_record/attribute_methods/primary_key.rb +62 -25
  24. data/lib/active_record/attribute_methods/read.rb +72 -83
  25. data/lib/active_record/attribute_methods/serialization.rb +93 -0
  26. data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -14
  27. data/lib/active_record/attribute_methods/write.rb +27 -5
  28. data/lib/active_record/attribute_methods.rb +209 -30
  29. data/lib/active_record/autosave_association.rb +23 -8
  30. data/lib/active_record/base.rb +217 -1709
  31. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +98 -132
  32. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +82 -29
  33. data/lib/active_record/connection_adapters/abstract/database_statements.rb +13 -42
  34. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
  35. data/lib/active_record/connection_adapters/abstract/quoting.rb +9 -12
  36. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +36 -25
  37. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +43 -22
  38. data/lib/active_record/connection_adapters/abstract_adapter.rb +78 -43
  39. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +653 -0
  40. data/lib/active_record/connection_adapters/column.rb +2 -2
  41. data/lib/active_record/connection_adapters/mysql2_adapter.rb +138 -578
  42. data/lib/active_record/connection_adapters/mysql_adapter.rb +86 -658
  43. data/lib/active_record/connection_adapters/postgresql_adapter.rb +144 -94
  44. data/lib/active_record/connection_adapters/schema_cache.rb +50 -0
  45. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -6
  46. data/lib/active_record/connection_adapters/sqlite_adapter.rb +43 -22
  47. data/lib/active_record/counter_cache.rb +4 -3
  48. data/lib/active_record/dynamic_matchers.rb +79 -0
  49. data/lib/active_record/errors.rb +11 -1
  50. data/lib/active_record/explain.rb +83 -0
  51. data/lib/active_record/explain_subscriber.rb +21 -0
  52. data/lib/active_record/fixtures/file.rb +65 -0
  53. data/lib/active_record/fixtures.rb +31 -76
  54. data/lib/active_record/identity_map.rb +4 -11
  55. data/lib/active_record/inheritance.rb +167 -0
  56. data/lib/active_record/integration.rb +49 -0
  57. data/lib/active_record/locking/optimistic.rb +30 -25
  58. data/lib/active_record/locking/pessimistic.rb +23 -1
  59. data/lib/active_record/log_subscriber.rb +3 -3
  60. data/lib/active_record/migration/command_recorder.rb +8 -8
  61. data/lib/active_record/migration.rb +47 -30
  62. data/lib/active_record/model_schema.rb +366 -0
  63. data/lib/active_record/nested_attributes.rb +3 -2
  64. data/lib/active_record/persistence.rb +51 -9
  65. data/lib/active_record/querying.rb +58 -0
  66. data/lib/active_record/railtie.rb +24 -28
  67. data/lib/active_record/railties/controller_runtime.rb +3 -1
  68. data/lib/active_record/railties/databases.rake +134 -77
  69. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  70. data/lib/active_record/readonly_attributes.rb +26 -0
  71. data/lib/active_record/reflection.rb +7 -15
  72. data/lib/active_record/relation/batches.rb +5 -2
  73. data/lib/active_record/relation/calculations.rb +27 -6
  74. data/lib/active_record/relation/delegation.rb +49 -0
  75. data/lib/active_record/relation/finder_methods.rb +6 -5
  76. data/lib/active_record/relation/predicate_builder.rb +12 -19
  77. data/lib/active_record/relation/query_methods.rb +76 -10
  78. data/lib/active_record/relation/spawn_methods.rb +11 -2
  79. data/lib/active_record/relation.rb +77 -34
  80. data/lib/active_record/result.rb +1 -1
  81. data/lib/active_record/sanitization.rb +194 -0
  82. data/lib/active_record/schema_dumper.rb +5 -2
  83. data/lib/active_record/scoping/default.rb +142 -0
  84. data/lib/active_record/scoping/named.rb +202 -0
  85. data/lib/active_record/scoping.rb +152 -0
  86. data/lib/active_record/serialization.rb +1 -43
  87. data/lib/active_record/serializers/xml_serializer.rb +2 -44
  88. data/lib/active_record/session_store.rb +15 -15
  89. data/lib/active_record/store.rb +50 -0
  90. data/lib/active_record/test_case.rb +11 -7
  91. data/lib/active_record/timestamp.rb +16 -3
  92. data/lib/active_record/transactions.rb +5 -5
  93. data/lib/active_record/translation.rb +22 -0
  94. data/lib/active_record/validations/associated.rb +5 -4
  95. data/lib/active_record/validations/uniqueness.rb +4 -4
  96. data/lib/active_record/validations.rb +1 -1
  97. data/lib/active_record/version.rb +2 -2
  98. data/lib/active_record.rb +28 -2
  99. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  100. data/lib/rails/generators/active_record/migration/templates/migration.rb +9 -3
  101. data/lib/rails/generators/active_record/model/model_generator.rb +5 -1
  102. data/lib/rails/generators/active_record/model/templates/migration.rb +3 -5
  103. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +1 -5
  104. metadata +50 -40
  105. checksums.yaml +0 -7
  106. data/lib/active_record/named_scope.rb +0 -200
@@ -1,8 +1,8 @@
1
1
  require 'active_support/core_ext/object/inclusion'
2
+ require 'active_record'
2
3
 
3
4
  db_namespace = namespace :db do
4
5
  task :load_config => :rails_env do
5
- require 'active_record'
6
6
  ActiveRecord::Base.configurations = Rails.application.config.database_configuration
7
7
  ActiveRecord::Migrator.migrations_paths = Rails.application.paths['db/migrate'].to_a
8
8
 
@@ -27,7 +27,7 @@ db_namespace = namespace :db do
27
27
  #
28
28
  # development:
29
29
  # database: blog_development
30
- # <<: *defaults
30
+ # *defaults
31
31
  next unless config['database']
32
32
  # Only connect to local databases
33
33
  local_database?(config) { create_database(config) }
@@ -37,11 +37,8 @@ db_namespace = namespace :db do
37
37
 
38
38
  desc 'Create the database from config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)'
39
39
  task :create => :load_config do
40
- # Make the test database at the same time as the development one, if it exists
41
- if Rails.env.development? && ActiveRecord::Base.configurations['test']
42
- create_database(ActiveRecord::Base.configurations['test'])
43
- end
44
- create_database(ActiveRecord::Base.configurations[Rails.env])
40
+ configs_for_environment.each { |config| create_database(config) }
41
+ ActiveRecord::Base.establish_connection(configs_for_environment.first)
45
42
  end
46
43
 
47
44
  def mysql_creation_options(config)
@@ -138,12 +135,7 @@ db_namespace = namespace :db do
138
135
 
139
136
  desc 'Drops the database for the current Rails.env (use db:drop:all to drop all databases)'
140
137
  task :drop => :load_config do
141
- config = ActiveRecord::Base.configurations[Rails.env || 'development']
142
- begin
143
- drop_database(config)
144
- rescue Exception => e
145
- $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
146
- end
138
+ configs_for_environment.each { |config| drop_database_and_rescue(config) }
147
139
  end
148
140
 
149
141
  def local_database?(config, &block)
@@ -158,8 +150,19 @@ db_namespace = namespace :db do
158
150
  desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
159
151
  task :migrate => [:environment, :load_config] do
160
152
  ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
161
- ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
162
- db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
153
+ ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration|
154
+ ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
155
+ end
156
+ db_namespace['_dump'].invoke
157
+ end
158
+
159
+ task :_dump do
160
+ case ActiveRecord::Base.schema_format
161
+ when :ruby then db_namespace["schema:dump"].invoke
162
+ when :sql then db_namespace["structure:dump"].invoke
163
+ else
164
+ raise "unknown schema format #{ActiveRecord::Base.schema_format}"
165
+ end
163
166
  end
164
167
 
165
168
  namespace :migrate do
@@ -182,7 +185,7 @@ db_namespace = namespace :db do
182
185
  version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
183
186
  raise 'VERSION is required' unless version
184
187
  ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
185
- db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
188
+ db_namespace['_dump'].invoke
186
189
  end
187
190
 
188
191
  # desc 'Runs the "down" for a given migration VERSION.'
@@ -190,7 +193,7 @@ db_namespace = namespace :db do
190
193
  version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
191
194
  raise 'VERSION is required' unless version
192
195
  ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
193
- db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
196
+ db_namespace['_dump'].invoke
194
197
  end
195
198
 
196
199
  desc 'Display status of migrations'
@@ -230,18 +233,21 @@ db_namespace = namespace :db do
230
233
  task :rollback => [:environment, :load_config] do
231
234
  step = ENV['STEP'] ? ENV['STEP'].to_i : 1
232
235
  ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
233
- db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
236
+ db_namespace['_dump'].invoke
234
237
  end
235
238
 
236
239
  # desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
237
240
  task :forward => [:environment, :load_config] do
238
241
  step = ENV['STEP'] ? ENV['STEP'].to_i : 1
239
242
  ActiveRecord::Migrator.forward(ActiveRecord::Migrator.migrations_paths, step)
240
- db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
243
+ db_namespace['_dump'].invoke
241
244
  end
242
245
 
243
246
  # desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
244
- task :reset => [ 'db:drop', 'db:setup' ]
247
+ task :reset => :environment do
248
+ db_namespace["drop"].invoke
249
+ db_namespace["setup"].invoke
250
+ end
245
251
 
246
252
  # desc "Retrieves the charset for the current environment's database"
247
253
  task :charset => :environment do
@@ -280,29 +286,28 @@ db_namespace = namespace :db do
280
286
 
281
287
  # desc "Raises an error if there are pending migrations"
282
288
  task :abort_if_pending_migrations => :environment do
283
- if defined? ActiveRecord
284
- pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_paths).pending_migrations
289
+ pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_paths).pending_migrations
285
290
 
286
- if pending_migrations.any?
287
- puts "You have #{pending_migrations.size} pending migrations:"
288
- pending_migrations.each do |pending_migration|
289
- puts ' %4d %s' % [pending_migration.version, pending_migration.name]
290
- end
291
- abort %{Run "rake db:migrate" to update your database then try again.}
291
+ if pending_migrations.any?
292
+ puts "You have #{pending_migrations.size} pending migrations:"
293
+ pending_migrations.each do |pending_migration|
294
+ puts ' %4d %s' % [pending_migration.version, pending_migration.name]
292
295
  end
296
+ abort %{Run `rake db:migrate` to update your database then try again.}
293
297
  end
294
298
  end
295
299
 
296
300
  desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)'
297
- task :setup => [ 'db:create', 'db:schema:load', 'db:seed' ]
301
+ task :setup => ['db:schema:load_if_ruby', 'db:structure:load_if_sql', :seed]
298
302
 
299
303
  desc 'Load the seed data from db/seeds.rb'
300
- task :seed => 'db:abort_if_pending_migrations' do
304
+ task :seed do
305
+ db_namespace['abort_if_pending_migrations'].invoke
301
306
  Rails.application.load_seed
302
307
  end
303
308
 
304
309
  namespace :fixtures do
305
- desc "Load 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."
310
+ desc "Load 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."
306
311
  task :load => :environment do
307
312
  require 'active_record/fixtures'
308
313
 
@@ -357,93 +362,125 @@ db_namespace = namespace :db do
357
362
  if File.exists?(file)
358
363
  load(file)
359
364
  else
360
- 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}
365
+ 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}
361
366
  end
362
367
  end
368
+
369
+ task :load_if_ruby => 'db:create' do
370
+ db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :ruby
371
+ end
363
372
  end
364
373
 
365
374
  namespace :structure do
366
- desc 'Dump the database structure to an SQL file'
375
+ desc 'Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql'
367
376
  task :dump => :environment do
368
377
  abcs = ActiveRecord::Base.configurations
378
+ filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
369
379
  case abcs[Rails.env]['adapter']
370
380
  when /mysql/, 'oci', 'oracle'
371
381
  ActiveRecord::Base.establish_connection(abcs[Rails.env])
372
- File.open("#{Rails.root}/db/#{Rails.env}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
382
+ File.open(filename, "w:utf-8") { |f| f << ActiveRecord::Base.connection.structure_dump }
373
383
  when /postgresql/
374
- ENV['PGHOST'] = abcs[Rails.env]['host'] if abcs[Rails.env]['host']
375
- ENV['PGPORT'] = abcs[Rails.env]["port"].to_s if abcs[Rails.env]['port']
376
- ENV['PGPASSWORD'] = abcs[Rails.env]['password'].to_s if abcs[Rails.env]['password']
384
+ set_psql_env(abcs[Rails.env])
377
385
  search_path = abcs[Rails.env]['schema_search_path']
378
386
  unless search_path.blank?
379
- search_path = search_path.split(",").map{|search_path| "--schema=#{search_path.strip}" }.join(" ")
387
+ search_path = search_path.split(",").map{|search_path_part| "--schema=#{search_path_part.strip}" }.join(" ")
380
388
  end
381
- `pg_dump -i -U "#{abcs[Rails.env]['username']}" -s -x -O -f db/#{Rails.env}_structure.sql #{search_path} #{abcs[Rails.env]['database']}`
389
+ `pg_dump -i -s -x -O -f #{filename} #{search_path} #{abcs[Rails.env]['database']}`
382
390
  raise 'Error dumping database' if $?.exitstatus == 1
383
391
  when /sqlite/
384
- dbfile = abcs[Rails.env]['database'] || abcs[Rails.env]['dbfile']
385
- `sqlite3 #{dbfile} .schema > db/#{Rails.env}_structure.sql`
392
+ dbfile = abcs[Rails.env]['database']
393
+ `sqlite3 #{dbfile} .schema > #{filename}`
386
394
  when 'sqlserver'
387
- `smoscript -s #{abcs[Rails.env]['host']} -d #{abcs[Rails.env]['database']} -u #{abcs[Rails.env]['username']} -p #{abcs[Rails.env]['password']} -f db\\#{Rails.env}_structure.sql -A -U`
395
+ `smoscript -s #{abcs[Rails.env]['host']} -d #{abcs[Rails.env]['database']} -u #{abcs[Rails.env]['username']} -p #{abcs[Rails.env]['password']} -f #{filename} -A -U`
388
396
  when "firebird"
389
397
  set_firebird_env(abcs[Rails.env])
390
398
  db_string = firebird_db_string(abcs[Rails.env])
391
- sh "isql -a #{db_string} > #{Rails.root}/db/#{Rails.env}_structure.sql"
399
+ sh "isql -a #{db_string} > #{filename}"
392
400
  else
393
401
  raise "Task not supported by '#{abcs[Rails.env]["adapter"]}'"
394
402
  end
395
403
 
396
404
  if ActiveRecord::Base.connection.supports_migrations?
397
- File.open("#{Rails.root}/db/#{Rails.env}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
405
+ File.open(filename, "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
398
406
  end
399
407
  end
400
- end
401
-
402
- namespace :test do
403
- # desc "Recreate the test database from the current schema.rb"
404
- task :load => 'db:test:purge' do
405
- ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
406
- ActiveRecord::Schema.verbose = false
407
- db_namespace['schema:load'].invoke
408
- end
409
408
 
410
- # desc "Recreate the test database from the current environment's database schema"
411
- task :clone => %w(db:schema:dump db:test:load)
409
+ # desc "Recreate the databases from the structure.sql file"
410
+ task :load => [:environment, :load_config] do
411
+ env = ENV['RAILS_ENV'] || 'test'
412
412
 
413
- # desc "Recreate the test databases from the development structure"
414
- task :clone_structure => [ 'db:structure:dump', 'db:test:purge' ] do
415
413
  abcs = ActiveRecord::Base.configurations
416
- case abcs['test']['adapter']
414
+ filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
415
+ case abcs[env]['adapter']
417
416
  when /mysql/
418
- ActiveRecord::Base.establish_connection(:test)
417
+ ActiveRecord::Base.establish_connection(abcs[env])
419
418
  ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
420
- IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split("\n\n").each do |table|
419
+ IO.read(filename).split("\n\n").each do |table|
421
420
  ActiveRecord::Base.connection.execute(table)
422
421
  end
423
422
  when /postgresql/
424
- ENV['PGHOST'] = abcs['test']['host'] if abcs['test']['host']
425
- ENV['PGPORT'] = abcs['test']['port'].to_s if abcs['test']['port']
426
- ENV['PGPASSWORD'] = abcs['test']['password'].to_s if abcs['test']['password']
427
- `psql -U "#{abcs['test']['username']}" -f "#{Rails.root}/db/#{Rails.env}_structure.sql" #{abcs['test']['database']} #{abcs['test']['template']}`
423
+ set_psql_env(abcs[env])
424
+ `psql -f "#{filename}" #{abcs[env]['database']} #{abcs[env]['template']}`
428
425
  when /sqlite/
429
- dbfile = abcs['test']['database'] || abcs['test']['dbfile']
430
- `sqlite3 #{dbfile} < "#{Rails.root}/db/#{Rails.env}_structure.sql"`
426
+ dbfile = abcs[env]['database']
427
+ `sqlite3 #{dbfile} < "#{filename}"`
431
428
  when 'sqlserver'
432
- `sqlcmd -S #{abcs['test']['host']} -d #{abcs['test']['database']} -U #{abcs['test']['username']} -P #{abcs['test']['password']} -i db\\#{Rails.env}_structure.sql`
429
+ `sqlcmd -S #{abcs[env]['host']} -d #{abcs[env]['database']} -U #{abcs[env]['username']} -P #{abcs[env]['password']} -i #{filename}`
433
430
  when 'oci', 'oracle'
434
- ActiveRecord::Base.establish_connection(:test)
435
- IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split(";\n\n").each do |ddl|
431
+ ActiveRecord::Base.establish_connection(abcs[env])
432
+ IO.read(filename).split(";\n\n").each do |ddl|
436
433
  ActiveRecord::Base.connection.execute(ddl)
437
434
  end
438
435
  when 'firebird'
439
- set_firebird_env(abcs['test'])
440
- db_string = firebird_db_string(abcs['test'])
441
- sh "isql -i #{Rails.root}/db/#{Rails.env}_structure.sql #{db_string}"
436
+ set_firebird_env(abcs[env])
437
+ db_string = firebird_db_string(abcs[env])
438
+ sh "isql -i #{filename} #{db_string}"
442
439
  else
443
- raise "Task not supported by '#{abcs['test']['adapter']}'"
440
+ raise "Task not supported by '#{abcs[env]['adapter']}'"
444
441
  end
445
442
  end
446
443
 
444
+ task :load_if_sql => 'db:create' do
445
+ db_namespace["structure:load"].invoke if ActiveRecord::Base.schema_format == :sql
446
+ end
447
+ end
448
+
449
+ namespace :test do
450
+
451
+ # desc "Recreate the test database from the current schema"
452
+ task :load => 'db:test:purge' do
453
+ case ActiveRecord::Base.schema_format
454
+ when :ruby
455
+ db_namespace["test:load_schema"].invoke
456
+ when :sql
457
+ db_namespace["test:load_structure"].invoke
458
+ end
459
+ end
460
+
461
+ # desc "Recreate the test database from an existent structure.sql file"
462
+ task :load_structure => 'db:test:purge' do
463
+ begin
464
+ old_env, ENV['RAILS_ENV'] = ENV['RAILS_ENV'], 'test'
465
+ db_namespace["structure:load"].invoke
466
+ ensure
467
+ ENV['RAILS_ENV'] = old_env
468
+ end
469
+ end
470
+
471
+ # desc "Recreate the test database from an existent schema.rb file"
472
+ task :load_schema => 'db:test:purge' do
473
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
474
+ ActiveRecord::Schema.verbose = false
475
+ db_namespace["schema:load"].invoke
476
+ end
477
+
478
+ # desc "Recreate the test database from a fresh schema.rb file"
479
+ task :clone => %w(db:schema:dump db:test:load_schema)
480
+
481
+ # desc "Recreate the test database from a fresh structure.sql file"
482
+ task :clone_structure => [ "db:structure:dump", "db:test:load_structure" ]
483
+
447
484
  # desc "Empty the test database"
448
485
  task :purge => :environment do
449
486
  abcs = ActiveRecord::Base.configurations
@@ -456,7 +493,7 @@ db_namespace = namespace :db do
456
493
  drop_database(abcs['test'])
457
494
  create_database(abcs['test'])
458
495
  when /sqlite/
459
- dbfile = abcs['test']['database'] || abcs['test']['dbfile']
496
+ dbfile = abcs['test']['database']
460
497
  File.delete(dbfile) if File.exist?(dbfile)
461
498
  when 'sqlserver'
462
499
  test = abcs.deep_dup['test']
@@ -479,7 +516,7 @@ db_namespace = namespace :db do
479
516
 
480
517
  # desc 'Check for pending migrations and load the test schema'
481
518
  task :prepare => 'db:abort_if_pending_migrations' do
482
- if defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
519
+ unless ActiveRecord::Base.configurations.blank?
483
520
  db_namespace[{ :sql => 'test:clone_structure', :ruby => 'test:load' }[ActiveRecord::Base.schema_format]].invoke
484
521
  end
485
522
  end
@@ -489,8 +526,7 @@ db_namespace = namespace :db do
489
526
  # desc "Creates a sessions migration for use with ActiveRecord::SessionStore"
490
527
  task :create => :environment do
491
528
  raise 'Task unavailable to this database (no migration support)' unless ActiveRecord::Base.connection.supports_migrations?
492
- require 'rails/generators'
493
- Rails::Generators.configure!
529
+ Rails.application.load_generators
494
530
  require 'rails/generators/rails/session_migration/session_migration_generator'
495
531
  Rails::Generators::SessionMigrationGenerator.start [ ENV['MIGRATION'] || 'add_sessions_table' ]
496
532
  end
@@ -549,6 +585,20 @@ def drop_database(config)
549
585
  end
550
586
  end
551
587
 
588
+ def drop_database_and_rescue(config)
589
+ begin
590
+ drop_database(config)
591
+ rescue Exception => e
592
+ $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
593
+ end
594
+ end
595
+
596
+ def configs_for_environment
597
+ environments = [Rails.env]
598
+ environments << 'test' if Rails.env.development?
599
+ ActiveRecord::Base.configurations.values_at(*environments).compact.reject { |config| config['database'].blank? }
600
+ end
601
+
552
602
  def session_table_name
553
603
  ActiveRecord::SessionStore::Session.table_name
554
604
  end
@@ -561,3 +611,10 @@ end
561
611
  def firebird_db_string(config)
562
612
  FireRuby::Database.db_string_for(config.symbolize_keys)
563
613
  end
614
+
615
+ def set_psql_env(config)
616
+ ENV['PGHOST'] = config['host'] if config['host']
617
+ ENV['PGPORT'] = config['port'].to_s if config['port']
618
+ ENV['PGPASSWORD'] = config['password'].to_s if config['password']
619
+ ENV['PGUSER'] = config['username'].to_s if config['username']
620
+ end
@@ -1,5 +1,5 @@
1
1
  #FIXME Remove if ArJdbcMysql will give.
2
- module ArJdbcMySQL
2
+ module ArJdbcMySQL #:nodoc:
3
3
  class Error < StandardError
4
4
  attr_accessor :error_number, :sql_state
5
5
 
@@ -0,0 +1,26 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/core_ext/class/attribute'
3
+
4
+ module ActiveRecord
5
+ module ReadonlyAttributes
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_attribute :_attr_readonly, :instance_writer => false
10
+ self._attr_readonly = []
11
+ end
12
+
13
+ module ClassMethods
14
+ # Attributes listed as readonly will be used to create a new record but update operations will
15
+ # ignore these fields.
16
+ def attr_readonly(*attributes)
17
+ self._attr_readonly = Set.new(attributes.map { |a| a.to_s }) + (self._attr_readonly || [])
18
+ end
19
+
20
+ # Returns an array of all the attributes that have been specified as readonly.
21
+ def readonly_attributes
22
+ self._attr_readonly
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,4 @@
1
1
  require 'active_support/core_ext/class/attribute'
2
- require 'active_support/core_ext/module/deprecation'
3
2
  require 'active_support/core_ext/object/inclusion'
4
3
 
5
4
  module ActiveRecord
@@ -125,7 +124,7 @@ module ActiveRecord
125
124
  # <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>'Money'</tt>
126
125
  # <tt>has_many :clients</tt> returns <tt>'Client'</tt>
127
126
  def class_name
128
- @class_name ||= options[:class_name] || derive_class_name
127
+ @class_name ||= (options[:class_name] || derive_class_name).to_s
129
128
  end
130
129
 
131
130
  # Returns +true+ if +self+ and +other_aggregation+ have the same +name+ attribute, +active_record+ attribute,
@@ -178,15 +177,9 @@ module ActiveRecord
178
177
  @collection = macro.in?([:has_many, :has_and_belongs_to_many])
179
178
  end
180
179
 
181
- # This is a hack so that we can tell if build_association was overridden, in order to
182
- # provide an appropriate deprecation if the overridden method ignored the &block. Please
183
- # see Association#build_record for details.
184
- attr_accessor :original_build_association_called # :nodoc
185
-
186
180
  # Returns a new, unsaved instance of the associated class. +options+ will
187
181
  # be passed to the class's constructor.
188
182
  def build_association(*options, &block)
189
- @original_build_association_called = true
190
183
  klass.new(*options, &block)
191
184
  end
192
185
 
@@ -202,11 +195,6 @@ module ActiveRecord
202
195
  @foreign_key ||= options[:foreign_key] || derive_foreign_key
203
196
  end
204
197
 
205
- def primary_key_name
206
- foreign_key
207
- end
208
- deprecate :primary_key_name => :foreign_key
209
-
210
198
  def foreign_type
211
199
  @foreign_type ||= options[:foreign_type] || "#{name}_type"
212
200
  end
@@ -274,6 +262,10 @@ module ActiveRecord
274
262
  [self]
275
263
  end
276
264
 
265
+ def nested?
266
+ false
267
+ end
268
+
277
269
  # An array of arrays of conditions. Each item in the outside array corresponds to a reflection
278
270
  # in the #chain. The inside arrays are simply conditions (and each condition may itself be
279
271
  # a hash, array, arel predicate, etc...)
@@ -381,7 +373,7 @@ module ActiveRecord
381
373
  delegate :foreign_key, :foreign_type, :association_foreign_key,
382
374
  :active_record_primary_key, :type, :to => :source_reflection
383
375
 
384
- # Gets the source of the through reflection. It checks both a singularized
376
+ # Gets the source of the through reflection. It checks both a singularized
385
377
  # and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
386
378
  #
387
379
  # class Post < ActiveRecord::Base
@@ -469,7 +461,7 @@ module ActiveRecord
469
461
  source_reflection.source_macro
470
462
  end
471
463
 
472
- # A through association is nested iff there would be more than one join table
464
+ # A through association is nested if there would be more than one join table
473
465
  def nested?
474
466
  chain.length > 2 || through_reflection.macro == :has_and_belongs_to_many
475
467
  end
@@ -66,11 +66,14 @@ module ActiveRecord
66
66
  records = relation.where(table[primary_key].gteq(start)).all
67
67
 
68
68
  while records.any?
69
+ records_size = records.size
70
+ primary_key_offset = records.last.id
71
+
69
72
  yield records
70
73
 
71
- break if records.size < batch_size
74
+ break if records_size < batch_size
72
75
 
73
- if primary_key_offset = records.last.id
76
+ if primary_key_offset
74
77
  records = relation.where(table[primary_key].gt(primary_key_offset)).to_a
75
78
  else
76
79
  raise "Primary key not included in the custom select clause"
@@ -66,7 +66,7 @@ module ActiveRecord
66
66
  calculate(:average, column_name, options)
67
67
  end
68
68
 
69
- # Calculates the minimum value on a given column. The value is returned
69
+ # Calculates the minimum value on a given column. The value is returned
70
70
  # with the same data type of the column, or +nil+ if there's no row. See
71
71
  # +calculate+ for examples with options.
72
72
  #
@@ -89,11 +89,15 @@ module ActiveRecord
89
89
  # +calculate+ for examples with options.
90
90
  #
91
91
  # Person.sum('age') # => 4562
92
- def sum(column_name, options = {})
93
- calculate(:sum, column_name, options)
92
+ def sum(*args)
93
+ if block_given?
94
+ self.to_a.sum(*args) {|*block_args| yield(*block_args)}
95
+ else
96
+ calculate(:sum, *args)
97
+ end
94
98
  end
95
99
 
96
- # This calculates aggregate values in the given column. Methods for count, sum, average,
100
+ # This calculates aggregate values in the given column. Methods for count, sum, average,
97
101
  # minimum, and maximum have been added as shortcuts. Options such as <tt>:conditions</tt>,
98
102
  # <tt>:order</tt>, <tt>:group</tt>, <tt>:having</tt>, and <tt>:joins</tt> can be passed to customize the query.
99
103
  #
@@ -101,7 +105,7 @@ module ActiveRecord
101
105
  # * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float
102
106
  # for AVG, and the given column's type for everything else.
103
107
  # * Grouped values: This returns an ordered hash of the values and groups them by the
104
- # <tt>:group</tt> option. It takes either a column name, or the name of a belongs_to association.
108
+ # <tt>:group</tt> option. It takes either a column name, or the name of a belongs_to association.
105
109
  #
106
110
  # values = Person.maximum(:age, :group => 'last_name')
107
111
  # puts values["Drake"]
@@ -119,7 +123,7 @@ module ActiveRecord
119
123
  # Options:
120
124
  # * <tt>:conditions</tt> - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ].
121
125
  # See conditions in the intro to ActiveRecord::Base.
122
- # * <tt>:include</tt>: Eager loading, see Associations for details. Since calculations don't load anything,
126
+ # * <tt>:include</tt>: Eager loading, see Associations for details. Since calculations don't load anything,
123
127
  # the purpose of this is to access fields on joined tables in your conditions, order, or group clauses.
124
128
  # * <tt>:joins</tt> - An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id".
125
129
  # (Rarely needed).
@@ -162,6 +166,23 @@ module ActiveRecord
162
166
  0
163
167
  end
164
168
 
169
+ # This method is designed to perform select by a single column as direct SQL query
170
+ # Returns <tt>Array</tt> with values of the specified column name
171
+ # The values has same data type as column.
172
+ #
173
+ # Examples:
174
+ #
175
+ # Person.pluck(:id) # SELECT people.id FROM people
176
+ # Person.uniq.pluck(:role) # SELECT DISTINCT role FROM people
177
+ # Person.where(:confirmed => true).limit(5).pluck(:id)
178
+ #
179
+ def pluck(column_name)
180
+ column_name = column_name.to_s
181
+ klass.connection.select_all(select(column_name).arel).map! do |attributes|
182
+ klass.type_cast_attribute(attributes.keys.first, klass.initialize_attributes(attributes))
183
+ end
184
+ end
185
+
165
186
  private
166
187
 
167
188
  def perform_calculation(operation, column_name, options = {})
@@ -0,0 +1,49 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ module ActiveRecord
4
+ module Delegation
5
+ # Set up common delegations for performance (avoids method_missing)
6
+ delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :to => :to_a
7
+ delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
8
+ :connection, :columns_hash, :auto_explain_threshold_in_seconds, :to => :klass
9
+
10
+ def self.delegate_to_scoped_klass(method)
11
+ if method.to_s =~ /\A[a-zA-Z_]\w*[!?]?\z/
12
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
13
+ def #{method}(*args, &block)
14
+ scoping { @klass.#{method}(*args, &block) }
15
+ end
16
+ RUBY
17
+ else
18
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
19
+ def #{method}(*args, &block)
20
+ scoping { @klass.send(#{method.inspect}, *args, &block) }
21
+ end
22
+ RUBY
23
+ end
24
+ end
25
+
26
+ def respond_to?(method, include_private = false)
27
+ super || Array.method_defined?(method) ||
28
+ @klass.respond_to?(method, include_private) ||
29
+ arel.respond_to?(method, include_private)
30
+ end
31
+
32
+ protected
33
+
34
+ def method_missing(method, *args, &block)
35
+ if Array.method_defined?(method)
36
+ ::ActiveRecord::Delegation.delegate method, :to => :to_a
37
+ to_a.send(method, *args, &block)
38
+ elsif @klass.respond_to?(method)
39
+ ::ActiveRecord::Delegation.delegate_to_scoped_klass(method)
40
+ scoping { @klass.send(method, *args, &block) }
41
+ elsif arel.respond_to?(method)
42
+ ::ActiveRecord::Delegation.delegate method, :to => :arel
43
+ arel.send(method, *args, &block)
44
+ else
45
+ super
46
+ end
47
+ end
48
+ end
49
+ end