activerecord 3.1.12 → 3.2.22.1

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