activerecord 3.1.9 → 3.2.12

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 (112) hide show
  1. checksums.yaml +6 -6
  2. data/CHANGELOG.md +317 -336
  3. data/README.rdoc +3 -3
  4. data/examples/performance.rb +20 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/associations/alias_tracker.rb +3 -6
  7. data/lib/active_record/associations/association.rb +3 -42
  8. data/lib/active_record/associations/association_scope.rb +3 -15
  9. data/lib/active_record/associations/builder/association.rb +6 -4
  10. data/lib/active_record/associations/builder/belongs_to.rb +3 -3
  11. data/lib/active_record/associations/builder/collection_association.rb +2 -2
  12. data/lib/active_record/associations/builder/has_many.rb +4 -4
  13. data/lib/active_record/associations/builder/has_one.rb +5 -6
  14. data/lib/active_record/associations/builder/singular_association.rb +3 -16
  15. data/lib/active_record/associations/collection_association.rb +64 -31
  16. data/lib/active_record/associations/collection_proxy.rb +2 -37
  17. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +1 -0
  18. data/lib/active_record/associations/has_many_association.rb +5 -1
  19. data/lib/active_record/associations/has_many_through_association.rb +28 -9
  20. data/lib/active_record/associations/has_one_association.rb +15 -13
  21. data/lib/active_record/associations/join_dependency.rb +2 -2
  22. data/lib/active_record/associations/preloader.rb +14 -10
  23. data/lib/active_record/associations/through_association.rb +7 -3
  24. data/lib/active_record/associations.rb +92 -76
  25. data/lib/active_record/attribute_assignment.rb +221 -0
  26. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
  27. data/lib/active_record/attribute_methods/dirty.rb +21 -11
  28. data/lib/active_record/attribute_methods/primary_key.rb +62 -25
  29. data/lib/active_record/attribute_methods/read.rb +73 -83
  30. data/lib/active_record/attribute_methods/serialization.rb +102 -0
  31. data/lib/active_record/attribute_methods/time_zone_conversion.rb +23 -17
  32. data/lib/active_record/attribute_methods/write.rb +31 -6
  33. data/lib/active_record/attribute_methods.rb +231 -30
  34. data/lib/active_record/autosave_association.rb +43 -22
  35. data/lib/active_record/base.rb +227 -1708
  36. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +150 -148
  37. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +85 -29
  38. data/lib/active_record/connection_adapters/abstract/database_statements.rb +6 -33
  39. data/lib/active_record/connection_adapters/abstract/query_cache.rb +10 -2
  40. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -6
  41. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -26
  42. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +48 -19
  43. data/lib/active_record/connection_adapters/abstract_adapter.rb +77 -42
  44. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +674 -0
  45. data/lib/active_record/connection_adapters/column.rb +37 -11
  46. data/lib/active_record/connection_adapters/mysql2_adapter.rb +129 -581
  47. data/lib/active_record/connection_adapters/mysql_adapter.rb +137 -696
  48. data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -86
  49. data/lib/active_record/connection_adapters/schema_cache.rb +50 -0
  50. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -6
  51. data/lib/active_record/connection_adapters/sqlite_adapter.rb +55 -32
  52. data/lib/active_record/counter_cache.rb +9 -4
  53. data/lib/active_record/dynamic_finder_match.rb +12 -0
  54. data/lib/active_record/dynamic_matchers.rb +84 -0
  55. data/lib/active_record/errors.rb +11 -1
  56. data/lib/active_record/explain.rb +85 -0
  57. data/lib/active_record/explain_subscriber.rb +25 -0
  58. data/lib/active_record/fixtures/file.rb +65 -0
  59. data/lib/active_record/fixtures.rb +56 -85
  60. data/lib/active_record/identity_map.rb +3 -4
  61. data/lib/active_record/inheritance.rb +174 -0
  62. data/lib/active_record/integration.rb +49 -0
  63. data/lib/active_record/locking/optimistic.rb +30 -25
  64. data/lib/active_record/locking/pessimistic.rb +23 -1
  65. data/lib/active_record/log_subscriber.rb +3 -3
  66. data/lib/active_record/migration/command_recorder.rb +8 -8
  67. data/lib/active_record/migration.rb +68 -35
  68. data/lib/active_record/model_schema.rb +366 -0
  69. data/lib/active_record/nested_attributes.rb +3 -2
  70. data/lib/active_record/persistence.rb +57 -11
  71. data/lib/active_record/querying.rb +58 -0
  72. data/lib/active_record/railtie.rb +31 -29
  73. data/lib/active_record/railties/controller_runtime.rb +3 -1
  74. data/lib/active_record/railties/databases.rake +191 -110
  75. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  76. data/lib/active_record/readonly_attributes.rb +26 -0
  77. data/lib/active_record/reflection.rb +7 -15
  78. data/lib/active_record/relation/batches.rb +5 -2
  79. data/lib/active_record/relation/calculations.rb +47 -15
  80. data/lib/active_record/relation/delegation.rb +49 -0
  81. data/lib/active_record/relation/finder_methods.rb +9 -7
  82. data/lib/active_record/relation/predicate_builder.rb +18 -7
  83. data/lib/active_record/relation/query_methods.rb +75 -9
  84. data/lib/active_record/relation/spawn_methods.rb +11 -2
  85. data/lib/active_record/relation.rb +78 -32
  86. data/lib/active_record/result.rb +1 -1
  87. data/lib/active_record/sanitization.rb +194 -0
  88. data/lib/active_record/schema_dumper.rb +12 -5
  89. data/lib/active_record/scoping/default.rb +142 -0
  90. data/lib/active_record/scoping/named.rb +202 -0
  91. data/lib/active_record/scoping.rb +152 -0
  92. data/lib/active_record/serialization.rb +1 -43
  93. data/lib/active_record/serializers/xml_serializer.rb +4 -45
  94. data/lib/active_record/session_store.rb +17 -15
  95. data/lib/active_record/store.rb +52 -0
  96. data/lib/active_record/test_case.rb +11 -7
  97. data/lib/active_record/timestamp.rb +17 -3
  98. data/lib/active_record/transactions.rb +27 -6
  99. data/lib/active_record/translation.rb +22 -0
  100. data/lib/active_record/validations/associated.rb +5 -4
  101. data/lib/active_record/validations/uniqueness.rb +7 -7
  102. data/lib/active_record/validations.rb +1 -1
  103. data/lib/active_record/version.rb +2 -2
  104. data/lib/active_record.rb +38 -3
  105. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -1
  106. data/lib/rails/generators/active_record/migration/templates/migration.rb +12 -3
  107. data/lib/rails/generators/active_record/model/model_generator.rb +9 -1
  108. data/lib/rails/generators/active_record/model/templates/migration.rb +3 -5
  109. data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
  110. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +1 -5
  111. metadata +30 -10
  112. data/lib/active_record/named_scope.rb +0 -200
@@ -1,8 +1,27 @@
1
1
  require 'active_support/core_ext/object/inclusion'
2
+ require 'active_record'
2
3
 
3
4
  db_namespace = namespace :db do
4
- task :load_config => :rails_env do
5
- require 'active_record'
5
+ def database_url_config
6
+ @database_url_config ||=
7
+ ActiveRecord::Base::ConnectionSpecification::Resolver.new(ENV["DATABASE_URL"], {}).spec.config.stringify_keys
8
+ end
9
+
10
+ def current_config(options = {})
11
+ options = { :env => Rails.env }.merge! options
12
+
13
+ if options[:config]
14
+ @current_config = options[:config]
15
+ else
16
+ @current_config ||= if ENV['DATABASE_URL']
17
+ database_url_config
18
+ else
19
+ ActiveRecord::Base.configurations[options[:env]]
20
+ end
21
+ end
22
+ end
23
+
24
+ task :load_config do
6
25
  ActiveRecord::Base.configurations = Rails.application.config.database_configuration
7
26
  ActiveRecord::Migrator.migrations_paths = Rails.application.paths['db/migrate'].to_a
8
27
 
@@ -27,7 +46,7 @@ db_namespace = namespace :db do
27
46
  #
28
47
  # development:
29
48
  # database: blog_development
30
- # <<: *defaults
49
+ # *defaults
31
50
  next unless config['database']
32
51
  # Only connect to local databases
33
52
  local_database?(config) { create_database(config) }
@@ -35,19 +54,20 @@ db_namespace = namespace :db do
35
54
  end
36
55
  end
37
56
 
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
- 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'])
57
+ desc 'Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)'
58
+ task :create => [:load_config, :rails_env] do
59
+ if ENV['DATABASE_URL']
60
+ create_database(database_url_config)
61
+ else
62
+ configs_for_environment.each { |config| create_database(config) }
63
+ ActiveRecord::Base.establish_connection(configs_for_environment.first)
43
64
  end
44
- create_database(ActiveRecord::Base.configurations[Rails.env])
45
65
  end
46
66
 
47
67
  def mysql_creation_options(config)
48
68
  @charset = ENV['CHARSET'] || 'utf8'
49
69
  @collation = ENV['COLLATION'] || 'utf8_unicode_ci'
50
- {:charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation)}
70
+ {:charset => (config['encoding'] || @charset), :collation => (config['collation'] || @collation)}
51
71
  end
52
72
 
53
73
  def create_database(config)
@@ -99,8 +119,8 @@ db_namespace = namespace :db do
99
119
  ActiveRecord::Base.establish_connection(config)
100
120
  else
101
121
  $stderr.puts sqlerr.error
102
- $stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['charset'] || @charset}, collation: #{config['collation'] || @collation}"
103
- $stderr.puts "(if you set the charset manually, make sure you have a matching collation)" if config['charset']
122
+ $stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['encoding'] || @charset}, collation: #{config['collation'] || @collation}"
123
+ $stderr.puts "(if you set the charset manually, make sure you have a matching collation)" if config['encoding']
104
124
  end
105
125
  end
106
126
  when /postgresql/
@@ -136,13 +156,12 @@ db_namespace = namespace :db do
136
156
  end
137
157
  end
138
158
 
139
- desc 'Drops the database for the current Rails.env (use db:drop:all to drop all databases)'
140
- 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}"
159
+ desc 'Drops the database using DATABASE_URL or the current Rails.env (use db:drop:all to drop all databases)'
160
+ task :drop => [:load_config, :rails_env] do
161
+ if ENV['DATABASE_URL']
162
+ drop_database_and_rescue(database_url_config)
163
+ else
164
+ configs_for_environment.each { |config| drop_database_and_rescue(config) }
146
165
  end
147
166
  end
148
167
 
@@ -154,12 +173,25 @@ db_namespace = namespace :db do
154
173
  end
155
174
  end
156
175
 
157
-
158
176
  desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
159
177
  task :migrate => [:environment, :load_config] do
160
178
  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
179
+ ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration|
180
+ ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
181
+ end
182
+ db_namespace['_dump'].invoke
183
+ end
184
+
185
+ task :_dump do
186
+ case ActiveRecord::Base.schema_format
187
+ when :ruby then db_namespace["schema:dump"].invoke
188
+ when :sql then db_namespace["structure:dump"].invoke
189
+ else
190
+ raise "unknown schema format #{ActiveRecord::Base.schema_format}"
191
+ end
192
+ # Allow this task to be called as many times as required. An example is the
193
+ # migrate:redo task, which calls other two internally that depend on this one.
194
+ db_namespace['_dump'].reenable
163
195
  end
164
196
 
165
197
  namespace :migrate do
@@ -182,7 +214,7 @@ db_namespace = namespace :db do
182
214
  version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
183
215
  raise 'VERSION is required' unless version
184
216
  ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
185
- db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
217
+ db_namespace['_dump'].invoke
186
218
  end
187
219
 
188
220
  # desc 'Runs the "down" for a given migration VERSION.'
@@ -190,13 +222,11 @@ db_namespace = namespace :db do
190
222
  version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
191
223
  raise 'VERSION is required' unless version
192
224
  ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
193
- db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
225
+ db_namespace['_dump'].invoke
194
226
  end
195
227
 
196
228
  desc 'Display status of migrations'
197
229
  task :status => [:environment, :load_config] do
198
- config = ActiveRecord::Base.configurations[Rails.env || 'development']
199
- ActiveRecord::Base.establish_connection(config)
200
230
  unless ActiveRecord::Base.connection.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name)
201
231
  puts 'Schema migrations table does not exist yet.'
202
232
  next # means "return" for rake task
@@ -216,7 +246,7 @@ db_namespace = namespace :db do
216
246
  ['up', version, '********** NO FILE **********']
217
247
  end
218
248
  # output
219
- puts "\ndatabase: #{config['database']}\n\n"
249
+ puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
220
250
  puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
221
251
  puts "-" * 50
222
252
  (db_list + file_list).sort_by {|migration| migration[1]}.each do |migration|
@@ -230,22 +260,25 @@ db_namespace = namespace :db do
230
260
  task :rollback => [:environment, :load_config] do
231
261
  step = ENV['STEP'] ? ENV['STEP'].to_i : 1
232
262
  ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
233
- db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
263
+ db_namespace['_dump'].invoke
234
264
  end
235
265
 
236
266
  # desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
237
267
  task :forward => [:environment, :load_config] do
238
268
  step = ENV['STEP'] ? ENV['STEP'].to_i : 1
239
269
  ActiveRecord::Migrator.forward(ActiveRecord::Migrator.migrations_paths, step)
240
- db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
270
+ db_namespace['_dump'].invoke
241
271
  end
242
272
 
243
273
  # 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' ]
274
+ task :reset => [:environment, :load_config] do
275
+ db_namespace["drop"].invoke
276
+ db_namespace["setup"].invoke
277
+ end
245
278
 
246
279
  # desc "Retrieves the charset for the current environment's database"
247
- task :charset => :environment do
248
- config = ActiveRecord::Base.configurations[Rails.env || 'development']
280
+ task :charset => [:environment, :load_config] do
281
+ config = ActiveRecord::Base.configurations[Rails.env]
249
282
  case config['adapter']
250
283
  when /mysql/
251
284
  ActiveRecord::Base.establish_connection(config)
@@ -262,8 +295,8 @@ db_namespace = namespace :db do
262
295
  end
263
296
 
264
297
  # desc "Retrieves the collation for the current environment's database"
265
- task :collation => :environment do
266
- config = ActiveRecord::Base.configurations[Rails.env || 'development']
298
+ task :collation => [:environment, :load_config] do
299
+ config = ActiveRecord::Base.configurations[Rails.env]
267
300
  case config['adapter']
268
301
  when /mysql/
269
302
  ActiveRecord::Base.establish_connection(config)
@@ -274,39 +307,37 @@ db_namespace = namespace :db do
274
307
  end
275
308
 
276
309
  desc 'Retrieves the current schema version number'
277
- task :version => :environment do
310
+ task :version => [:environment, :load_config] do
278
311
  puts "Current version: #{ActiveRecord::Migrator.current_version}"
279
312
  end
280
313
 
281
314
  # desc "Raises an error if there are pending migrations"
282
- task :abort_if_pending_migrations => :environment do
283
- if defined? ActiveRecord
284
- pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_paths).pending_migrations
285
-
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.}
315
+ task :abort_if_pending_migrations => [:environment, :load_config] do
316
+ pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_paths).pending_migrations
317
+
318
+ if pending_migrations.any?
319
+ puts "You have #{pending_migrations.size} pending migrations:"
320
+ pending_migrations.each do |pending_migration|
321
+ puts ' %4d %s' % [pending_migration.version, pending_migration.name]
292
322
  end
323
+ abort %{Run `rake db:migrate` to update your database then try again.}
293
324
  end
294
325
  end
295
326
 
296
327
  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' ]
328
+ task :setup => ['db:schema:load_if_ruby', 'db:structure:load_if_sql', :seed]
298
329
 
299
330
  desc 'Load the seed data from db/seeds.rb'
300
- task :seed => 'db:abort_if_pending_migrations' do
331
+ task :seed do
332
+ db_namespace['abort_if_pending_migrations'].invoke
301
333
  Rails.application.load_seed
302
334
  end
303
335
 
304
336
  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."
306
- task :load => :environment do
337
+ 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."
338
+ task :load => [:environment, :load_config] do
307
339
  require 'active_record/fixtures'
308
340
 
309
- ActiveRecord::Base.establish_connection(Rails.env)
310
341
  base_dir = File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
311
342
  fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact
312
343
 
@@ -316,7 +347,7 @@ db_namespace = namespace :db do
316
347
  end
317
348
 
318
349
  # desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
319
- task :identify => :environment do
350
+ task :identify => [:environment, :load_config] do
320
351
  require 'active_record/fixtures'
321
352
 
322
353
  label, id = ENV['LABEL'], ENV['ID']
@@ -345,107 +376,137 @@ db_namespace = namespace :db do
345
376
  require 'active_record/schema_dumper'
346
377
  filename = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
347
378
  File.open(filename, "w:utf-8") do |file|
348
- ActiveRecord::Base.establish_connection(Rails.env)
349
379
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
350
380
  end
351
381
  db_namespace['schema:dump'].reenable
352
382
  end
353
383
 
354
384
  desc 'Load a schema.rb file into the database'
355
- task :load => :environment do
385
+ task :load => [:environment, :load_config] do
356
386
  file = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
357
387
  if File.exists?(file)
358
388
  load(file)
359
389
  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}
390
+ 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
391
  end
362
392
  end
393
+
394
+ task :load_if_ruby => ['db:create', :environment] do
395
+ db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :ruby
396
+ end
363
397
  end
364
398
 
365
399
  namespace :structure do
366
- desc 'Dump the database structure to an SQL file'
367
- task :dump => :environment do
368
- abcs = ActiveRecord::Base.configurations
369
- case abcs[Rails.env]['adapter']
400
+ desc 'Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql'
401
+ task :dump => [:environment, :load_config] do
402
+ config = current_config
403
+ filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
404
+ case config['adapter']
370
405
  when /mysql/, 'oci', 'oracle'
371
- 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 }
406
+ ActiveRecord::Base.establish_connection(config)
407
+ File.open(filename, "w:utf-8") { |f| f << ActiveRecord::Base.connection.structure_dump }
373
408
  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']
377
- search_path = abcs[Rails.env]['schema_search_path']
409
+ set_psql_env(config)
410
+ search_path = config['schema_search_path']
378
411
  unless search_path.blank?
379
- search_path = search_path.split(",").map{|search_path| "--schema=#{search_path.strip}" }.join(" ")
412
+ search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
380
413
  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']}`
414
+ `pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(config['database'])}`
382
415
  raise 'Error dumping database' if $?.exitstatus == 1
383
416
  when /sqlite/
384
- dbfile = abcs[Rails.env]['database'] || abcs[Rails.env]['dbfile']
385
- `sqlite3 #{dbfile} .schema > db/#{Rails.env}_structure.sql`
417
+ dbfile = config['database']
418
+ `sqlite3 #{dbfile} .schema > #{filename}`
386
419
  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`
420
+ `smoscript -s #{config['host']} -d #{config['database']} -u #{config['username']} -p #{config['password']} -f #{filename} -A -U`
388
421
  when "firebird"
389
422
  set_firebird_env(abcs[Rails.env])
390
423
  db_string = firebird_db_string(abcs[Rails.env])
391
- sh "isql -a #{db_string} > #{Rails.root}/db/#{Rails.env}_structure.sql"
424
+ sh "isql -a #{db_string} > #{filename}"
392
425
  else
393
426
  raise "Task not supported by '#{abcs[Rails.env]["adapter"]}'"
394
427
  end
395
428
 
396
429
  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 }
430
+ File.open(filename, "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
398
431
  end
432
+ db_namespace['structure:dump'].reenable
399
433
  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
-
410
- # desc "Recreate the test database from the current environment's database schema"
411
- task :clone => %w(db:schema:dump db:test:load)
412
434
 
413
- # desc "Recreate the test databases from the development structure"
414
- task :clone_structure => [ 'db:structure:dump', 'db:test:purge' ] do
415
- abcs = ActiveRecord::Base.configurations
416
- case abcs['test']['adapter']
435
+ # desc "Recreate the databases from the structure.sql file"
436
+ task :load => [:environment, :load_config] do
437
+ config = current_config
438
+ filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
439
+ case config['adapter']
417
440
  when /mysql/
418
- ActiveRecord::Base.establish_connection(:test)
441
+ ActiveRecord::Base.establish_connection(config)
419
442
  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|
443
+ IO.read(filename).split("\n\n").each do |table|
421
444
  ActiveRecord::Base.connection.execute(table)
422
445
  end
423
446
  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']}`
447
+ set_psql_env(config)
448
+ `psql -f "#{filename}" #{config['database']}`
428
449
  when /sqlite/
429
- dbfile = abcs['test']['database'] || abcs['test']['dbfile']
430
- `sqlite3 #{dbfile} < "#{Rails.root}/db/#{Rails.env}_structure.sql"`
450
+ dbfile = config['database']
451
+ `sqlite3 #{dbfile} < "#{filename}"`
431
452
  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`
453
+ `sqlcmd -S #{config['host']} -d #{config['database']} -U #{config['username']} -P #{config['password']} -i #{filename}`
433
454
  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|
455
+ ActiveRecord::Base.establish_connection(config)
456
+ IO.read(filename).split(";\n\n").each do |ddl|
436
457
  ActiveRecord::Base.connection.execute(ddl)
437
458
  end
438
459
  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}"
460
+ set_firebird_env(config)
461
+ db_string = firebird_db_string(config)
462
+ sh "isql -i #{filename} #{db_string}"
442
463
  else
443
- raise "Task not supported by '#{abcs['test']['adapter']}'"
464
+ raise "Task not supported by '#{config['adapter']}'"
465
+ end
466
+ end
467
+
468
+ task :load_if_sql => ['db:create', :environment] do
469
+ db_namespace["structure:load"].invoke if ActiveRecord::Base.schema_format == :sql
470
+ end
471
+ end
472
+
473
+ namespace :test do
474
+
475
+ # desc "Recreate the test database from the current schema"
476
+ task :load => 'db:test:purge' do
477
+ case ActiveRecord::Base.schema_format
478
+ when :ruby
479
+ db_namespace["test:load_schema"].invoke
480
+ when :sql
481
+ db_namespace["test:load_structure"].invoke
444
482
  end
445
483
  end
446
484
 
485
+ # desc "Recreate the test database from an existent structure.sql file"
486
+ task :load_structure => 'db:test:purge' do
487
+ begin
488
+ current_config(:config => ActiveRecord::Base.configurations['test'])
489
+ db_namespace["structure:load"].invoke
490
+ ensure
491
+ current_config(:config => nil)
492
+ end
493
+ end
494
+
495
+ # desc "Recreate the test database from an existent schema.rb file"
496
+ task :load_schema => 'db:test:purge' do
497
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
498
+ ActiveRecord::Schema.verbose = false
499
+ db_namespace["schema:load"].invoke
500
+ end
501
+
502
+ # desc "Recreate the test database from a fresh schema.rb file"
503
+ task :clone => %w(db:schema:dump db:test:load_schema)
504
+
505
+ # desc "Recreate the test database from a fresh structure.sql file"
506
+ task :clone_structure => [ "db:structure:dump", "db:test:load_structure" ]
507
+
447
508
  # desc "Empty the test database"
448
- task :purge => :environment do
509
+ task :purge => [:environment, :load_config] do
449
510
  abcs = ActiveRecord::Base.configurations
450
511
  case abcs['test']['adapter']
451
512
  when /mysql/
@@ -456,7 +517,7 @@ db_namespace = namespace :db do
456
517
  drop_database(abcs['test'])
457
518
  create_database(abcs['test'])
458
519
  when /sqlite/
459
- dbfile = abcs['test']['database'] || abcs['test']['dbfile']
520
+ dbfile = abcs['test']['database']
460
521
  File.delete(dbfile) if File.exist?(dbfile)
461
522
  when 'sqlserver'
462
523
  test = abcs.deep_dup['test']
@@ -479,7 +540,7 @@ db_namespace = namespace :db do
479
540
 
480
541
  # desc 'Check for pending migrations and load the test schema'
481
542
  task :prepare => 'db:abort_if_pending_migrations' do
482
- if defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
543
+ unless ActiveRecord::Base.configurations.blank?
483
544
  db_namespace[{ :sql => 'test:clone_structure', :ruby => 'test:load' }[ActiveRecord::Base.schema_format]].invoke
484
545
  end
485
546
  end
@@ -487,16 +548,15 @@ db_namespace = namespace :db do
487
548
 
488
549
  namespace :sessions do
489
550
  # desc "Creates a sessions migration for use with ActiveRecord::SessionStore"
490
- task :create => :environment do
551
+ task :create => [:environment, :load_config] do
491
552
  raise 'Task unavailable to this database (no migration support)' unless ActiveRecord::Base.connection.supports_migrations?
492
- require 'rails/generators'
493
- Rails::Generators.configure!
553
+ Rails.application.load_generators
494
554
  require 'rails/generators/rails/session_migration/session_migration_generator'
495
555
  Rails::Generators::SessionMigrationGenerator.start [ ENV['MIGRATION'] || 'add_sessions_table' ]
496
556
  end
497
557
 
498
558
  # desc "Clear the sessions table"
499
- task :clear => :environment do
559
+ task :clear => [:environment, :load_config] do
500
560
  ActiveRecord::Base.connection.execute "DELETE FROM #{session_table_name}"
501
561
  end
502
562
  end
@@ -524,7 +584,7 @@ namespace :railties do
524
584
  puts "Copied migration #{migration.basename} from #{name}"
525
585
  end
526
586
 
527
- ActiveRecord::Migration.copy( ActiveRecord::Migrator.migrations_paths.first, railties,
587
+ ActiveRecord::Migration.copy(ActiveRecord::Migrator.migrations_paths.first, railties,
528
588
  :on_skip => on_skip, :on_copy => on_copy)
529
589
  end
530
590
  end
@@ -549,6 +609,20 @@ def drop_database(config)
549
609
  end
550
610
  end
551
611
 
612
+ def drop_database_and_rescue(config)
613
+ begin
614
+ drop_database(config)
615
+ rescue Exception => e
616
+ $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
617
+ end
618
+ end
619
+
620
+ def configs_for_environment
621
+ environments = [Rails.env]
622
+ environments << 'test' if Rails.env.development?
623
+ ActiveRecord::Base.configurations.values_at(*environments).compact.reject { |config| config['database'].blank? }
624
+ end
625
+
552
626
  def session_table_name
553
627
  ActiveRecord::SessionStore::Session.table_name
554
628
  end
@@ -561,3 +635,10 @@ end
561
635
  def firebird_db_string(config)
562
636
  FireRuby::Database.db_string_for(config.symbolize_keys)
563
637
  end
638
+
639
+ def set_psql_env(config)
640
+ ENV['PGHOST'] = config['host'] if config['host']
641
+ ENV['PGPORT'] = config['port'].to_s if config['port']
642
+ ENV['PGPASSWORD'] = config['password'].to_s if config['password']
643
+ ENV['PGUSER'] = config['username'].to_s if config['username']
644
+ 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"