activerecord 3.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (93) hide show
  1. data/CHANGELOG +6023 -0
  2. data/README.rdoc +222 -0
  3. data/examples/associations.png +0 -0
  4. data/examples/performance.rb +162 -0
  5. data/examples/simple.rb +14 -0
  6. data/lib/active_record.rb +124 -0
  7. data/lib/active_record/aggregations.rb +277 -0
  8. data/lib/active_record/association_preload.rb +403 -0
  9. data/lib/active_record/associations.rb +2254 -0
  10. data/lib/active_record/associations/association_collection.rb +562 -0
  11. data/lib/active_record/associations/association_proxy.rb +295 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +91 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +78 -0
  14. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +137 -0
  15. data/lib/active_record/associations/has_many_association.rb +128 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +116 -0
  17. data/lib/active_record/associations/has_one_association.rb +143 -0
  18. data/lib/active_record/associations/has_one_through_association.rb +40 -0
  19. data/lib/active_record/associations/through_association_scope.rb +154 -0
  20. data/lib/active_record/attribute_methods.rb +60 -0
  21. data/lib/active_record/attribute_methods/before_type_cast.rb +33 -0
  22. data/lib/active_record/attribute_methods/dirty.rb +95 -0
  23. data/lib/active_record/attribute_methods/primary_key.rb +50 -0
  24. data/lib/active_record/attribute_methods/query.rb +39 -0
  25. data/lib/active_record/attribute_methods/read.rb +116 -0
  26. data/lib/active_record/attribute_methods/time_zone_conversion.rb +61 -0
  27. data/lib/active_record/attribute_methods/write.rb +37 -0
  28. data/lib/active_record/autosave_association.rb +369 -0
  29. data/lib/active_record/base.rb +1867 -0
  30. data/lib/active_record/callbacks.rb +288 -0
  31. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +365 -0
  32. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +113 -0
  33. data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
  34. data/lib/active_record/connection_adapters/abstract/database_statements.rb +329 -0
  35. data/lib/active_record/connection_adapters/abstract/query_cache.rb +81 -0
  36. data/lib/active_record/connection_adapters/abstract/quoting.rb +72 -0
  37. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +739 -0
  38. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +543 -0
  39. data/lib/active_record/connection_adapters/abstract_adapter.rb +212 -0
  40. data/lib/active_record/connection_adapters/mysql_adapter.rb +643 -0
  41. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1030 -0
  42. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +53 -0
  43. data/lib/active_record/connection_adapters/sqlite_adapter.rb +401 -0
  44. data/lib/active_record/counter_cache.rb +115 -0
  45. data/lib/active_record/dynamic_finder_match.rb +53 -0
  46. data/lib/active_record/dynamic_scope_match.rb +32 -0
  47. data/lib/active_record/errors.rb +172 -0
  48. data/lib/active_record/fixtures.rb +1008 -0
  49. data/lib/active_record/locale/en.yml +40 -0
  50. data/lib/active_record/locking/optimistic.rb +172 -0
  51. data/lib/active_record/locking/pessimistic.rb +55 -0
  52. data/lib/active_record/log_subscriber.rb +48 -0
  53. data/lib/active_record/migration.rb +617 -0
  54. data/lib/active_record/named_scope.rb +138 -0
  55. data/lib/active_record/nested_attributes.rb +417 -0
  56. data/lib/active_record/observer.rb +140 -0
  57. data/lib/active_record/persistence.rb +291 -0
  58. data/lib/active_record/query_cache.rb +36 -0
  59. data/lib/active_record/railtie.rb +91 -0
  60. data/lib/active_record/railties/controller_runtime.rb +38 -0
  61. data/lib/active_record/railties/databases.rake +512 -0
  62. data/lib/active_record/reflection.rb +403 -0
  63. data/lib/active_record/relation.rb +393 -0
  64. data/lib/active_record/relation/batches.rb +89 -0
  65. data/lib/active_record/relation/calculations.rb +286 -0
  66. data/lib/active_record/relation/finder_methods.rb +355 -0
  67. data/lib/active_record/relation/predicate_builder.rb +41 -0
  68. data/lib/active_record/relation/query_methods.rb +261 -0
  69. data/lib/active_record/relation/spawn_methods.rb +112 -0
  70. data/lib/active_record/schema.rb +59 -0
  71. data/lib/active_record/schema_dumper.rb +195 -0
  72. data/lib/active_record/serialization.rb +60 -0
  73. data/lib/active_record/serializers/xml_serializer.rb +244 -0
  74. data/lib/active_record/session_store.rb +340 -0
  75. data/lib/active_record/test_case.rb +67 -0
  76. data/lib/active_record/timestamp.rb +88 -0
  77. data/lib/active_record/transactions.rb +356 -0
  78. data/lib/active_record/validations.rb +84 -0
  79. data/lib/active_record/validations/associated.rb +48 -0
  80. data/lib/active_record/validations/uniqueness.rb +185 -0
  81. data/lib/active_record/version.rb +9 -0
  82. data/lib/rails/generators/active_record.rb +27 -0
  83. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  84. data/lib/rails/generators/active_record/migration/templates/migration.rb +17 -0
  85. data/lib/rails/generators/active_record/model/model_generator.rb +38 -0
  86. data/lib/rails/generators/active_record/model/templates/migration.rb +16 -0
  87. data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
  88. data/lib/rails/generators/active_record/model/templates/module.rb +5 -0
  89. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  90. data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
  91. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +24 -0
  92. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +16 -0
  93. metadata +224 -0
@@ -0,0 +1,91 @@
1
+ require "active_record"
2
+ require "rails"
3
+ require "active_model/railtie"
4
+
5
+ # For now, action_controller must always be present with
6
+ # rails, so let's make sure that it gets required before
7
+ # here. This is needed for correctly setting up the middleware.
8
+ # In the future, this might become an optional require.
9
+ require "action_controller/railtie"
10
+
11
+ module ActiveRecord
12
+ # = Active Record Railtie
13
+ class Railtie < Rails::Railtie
14
+ config.active_record = ActiveSupport::OrderedOptions.new
15
+
16
+ config.generators.orm :active_record, :migration => true,
17
+ :timestamps => true
18
+
19
+ config.app_middleware.insert_after "::ActionDispatch::Callbacks",
20
+ "ActiveRecord::QueryCache"
21
+
22
+ config.app_middleware.insert_after "::ActionDispatch::Callbacks",
23
+ "ActiveRecord::ConnectionAdapters::ConnectionManagement"
24
+
25
+ rake_tasks do
26
+ load "active_record/railties/databases.rake"
27
+ end
28
+
29
+ # When loading console, force ActiveRecord to be loaded to avoid cross
30
+ # references when loading a constant for the first time.
31
+ console do
32
+ ActiveRecord::Base
33
+ end
34
+
35
+ initializer "active_record.initialize_timezone" do
36
+ ActiveSupport.on_load(:active_record) do
37
+ self.time_zone_aware_attributes = true
38
+ self.default_timezone = :utc
39
+ end
40
+ end
41
+
42
+ initializer "active_record.logger" do
43
+ ActiveSupport.on_load(:active_record) { self.logger ||= ::Rails.logger }
44
+ end
45
+
46
+ initializer "active_record.set_configs" do |app|
47
+ ActiveSupport.on_load(:active_record) do
48
+ app.config.active_record.each do |k,v|
49
+ send "#{k}=", v
50
+ end
51
+ end
52
+ end
53
+
54
+ # This sets the database configuration from Configuration#database_configuration
55
+ # and then establishes the connection.
56
+ initializer "active_record.initialize_database" do |app|
57
+ ActiveSupport.on_load(:active_record) do
58
+ self.configurations = app.config.database_configuration
59
+ establish_connection
60
+ end
61
+ end
62
+
63
+ # Expose database runtime to controller for logging.
64
+ initializer "active_record.log_runtime" do |app|
65
+ require "active_record/railties/controller_runtime"
66
+ ActiveSupport.on_load(:action_controller) do
67
+ include ActiveRecord::Railties::ControllerRuntime
68
+ end
69
+ end
70
+
71
+ initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app|
72
+ unless app.config.cache_classes
73
+ ActiveSupport.on_load(:active_record) do
74
+ ActionDispatch::Callbacks.after do
75
+ ActiveRecord::Base.clear_reloadable_connections!
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ config.after_initialize do
82
+ ActiveSupport.on_load(:active_record) do
83
+ instantiate_observers
84
+
85
+ ActionDispatch::Callbacks.to_prepare(:activerecord_instantiate_observers) do
86
+ ActiveRecord::Base.instantiate_observers
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,38 @@
1
+ require 'active_support/core_ext/module/attr_internal'
2
+
3
+ module ActiveRecord
4
+ module Railties
5
+ module ControllerRuntime
6
+ extend ActiveSupport::Concern
7
+
8
+ protected
9
+
10
+ attr_internal :db_runtime
11
+
12
+ def cleanup_view_runtime
13
+ if ActiveRecord::Base.connected?
14
+ db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
15
+ runtime = super
16
+ db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime
17
+ self.db_runtime = db_rt_before_render + db_rt_after_render
18
+ runtime - db_rt_after_render
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ def append_info_to_payload(payload)
25
+ super
26
+ payload[:db_runtime] = db_runtime
27
+ end
28
+
29
+ module ClassMethods
30
+ def log_process_action(payload)
31
+ messages, db_runtime = super, payload[:db_runtime]
32
+ messages << ("ActiveRecord: %.1fms" % db_runtime.to_f) if db_runtime
33
+ messages
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,512 @@
1
+ namespace :db do
2
+ task :load_config => :rails_env do
3
+ require 'active_record'
4
+ ActiveRecord::Base.configurations = Rails.application.config.database_configuration
5
+ end
6
+
7
+ namespace :create do
8
+ # desc 'Create all the local databases defined in config/database.yml'
9
+ task :all => :load_config do
10
+ ActiveRecord::Base.configurations.each_value do |config|
11
+ # Skip entries that don't have a database key, such as the first entry here:
12
+ #
13
+ # defaults: &defaults
14
+ # adapter: mysql
15
+ # username: root
16
+ # password:
17
+ # host: localhost
18
+ #
19
+ # development:
20
+ # database: blog_development
21
+ # <<: *defaults
22
+ next unless config['database']
23
+ # Only connect to local databases
24
+ local_database?(config) { create_database(config) }
25
+ end
26
+ end
27
+ end
28
+
29
+ desc 'Create the database from config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)'
30
+ task :create => :load_config do
31
+ # Make the test database at the same time as the development one, if it exists
32
+ if Rails.env.development? && ActiveRecord::Base.configurations['test']
33
+ create_database(ActiveRecord::Base.configurations['test'])
34
+ end
35
+ create_database(ActiveRecord::Base.configurations[Rails.env])
36
+ end
37
+
38
+ def create_database(config)
39
+ begin
40
+ if config['adapter'] =~ /sqlite/
41
+ if File.exist?(config['database'])
42
+ $stderr.puts "#{config['database']} already exists"
43
+ else
44
+ begin
45
+ # Create the SQLite database
46
+ ActiveRecord::Base.establish_connection(config)
47
+ ActiveRecord::Base.connection
48
+ rescue
49
+ $stderr.puts $!, *($!.backtrace)
50
+ $stderr.puts "Couldn't create database for #{config.inspect}"
51
+ end
52
+ end
53
+ return # Skip the else clause of begin/rescue
54
+ else
55
+ ActiveRecord::Base.establish_connection(config)
56
+ ActiveRecord::Base.connection
57
+ end
58
+ rescue
59
+ case config['adapter']
60
+ when /mysql/
61
+ @charset = ENV['CHARSET'] || 'utf8'
62
+ @collation = ENV['COLLATION'] || 'utf8_unicode_ci'
63
+ creation_options = {:charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation)}
64
+ error_class = config['adapter'] =~ /mysql2/ ? Mysql2::Error : Mysql::Error
65
+ access_denied_error = 1045
66
+ begin
67
+ ActiveRecord::Base.establish_connection(config.merge('database' => nil))
68
+ ActiveRecord::Base.connection.create_database(config['database'], creation_options)
69
+ ActiveRecord::Base.establish_connection(config)
70
+ rescue error_class => sqlerr
71
+ if sqlerr.errno == access_denied_error
72
+ print "#{sqlerr.error}. \nPlease provide the root password for your mysql installation\n>"
73
+ root_password = $stdin.gets.strip
74
+ grant_statement = "GRANT ALL PRIVILEGES ON #{config['database']}.* " \
75
+ "TO '#{config['username']}'@'localhost' " \
76
+ "IDENTIFIED BY '#{config['password']}' WITH GRANT OPTION;"
77
+ ActiveRecord::Base.establish_connection(config.merge(
78
+ 'database' => nil, 'username' => 'root', 'password' => root_password))
79
+ ActiveRecord::Base.connection.create_database(config['database'], creation_options)
80
+ ActiveRecord::Base.connection.execute grant_statement
81
+ ActiveRecord::Base.establish_connection(config)
82
+ else
83
+ $stderr.puts sqlerr.error
84
+ $stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['charset'] || @charset}, collation: #{config['collation'] || @collation}"
85
+ $stderr.puts "(if you set the charset manually, make sure you have a matching collation)" if config['charset']
86
+ end
87
+ end
88
+ when 'postgresql'
89
+ @encoding = config[:encoding] || ENV['CHARSET'] || 'utf8'
90
+ begin
91
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
92
+ ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding))
93
+ ActiveRecord::Base.establish_connection(config)
94
+ rescue
95
+ $stderr.puts $!, *($!.backtrace)
96
+ $stderr.puts "Couldn't create database for #{config.inspect}"
97
+ end
98
+ end
99
+ else
100
+ $stderr.puts "#{config['database']} already exists"
101
+ end
102
+ end
103
+
104
+ namespace :drop do
105
+ # desc 'Drops all the local databases defined in config/database.yml'
106
+ task :all => :load_config do
107
+ ActiveRecord::Base.configurations.each_value do |config|
108
+ # Skip entries that don't have a database key
109
+ next unless config['database']
110
+ begin
111
+ # Only connect to local databases
112
+ local_database?(config) { drop_database(config) }
113
+ rescue Exception => e
114
+ $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ desc 'Drops the database for the current Rails.env (use db:drop:all to drop all databases)'
121
+ task :drop => :load_config do
122
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
123
+ begin
124
+ drop_database(config)
125
+ rescue Exception => e
126
+ $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
127
+ end
128
+ end
129
+
130
+ def local_database?(config, &block)
131
+ if %w( 127.0.0.1 localhost ).include?(config['host']) || config['host'].blank?
132
+ yield
133
+ else
134
+ $stderr.puts "This task only modifies local databases. #{config['database']} is on a remote host."
135
+ end
136
+ end
137
+
138
+
139
+ desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
140
+ task :migrate => :environment do
141
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
142
+ ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
143
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
144
+ end
145
+
146
+ namespace :migrate do
147
+ # desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
148
+ task :redo => :environment do
149
+ if ENV["VERSION"]
150
+ Rake::Task["db:migrate:down"].invoke
151
+ Rake::Task["db:migrate:up"].invoke
152
+ else
153
+ Rake::Task["db:rollback"].invoke
154
+ Rake::Task["db:migrate"].invoke
155
+ end
156
+ end
157
+
158
+ # desc 'Resets your database using your migrations for the current environment'
159
+ task :reset => ["db:drop", "db:create", "db:migrate"]
160
+
161
+ # desc 'Runs the "up" for a given migration VERSION.'
162
+ task :up => :environment do
163
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
164
+ raise "VERSION is required" unless version
165
+ ActiveRecord::Migrator.run(:up, "db/migrate/", version)
166
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
167
+ end
168
+
169
+ # desc 'Runs the "down" for a given migration VERSION.'
170
+ task :down => :environment do
171
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
172
+ raise "VERSION is required" unless version
173
+ ActiveRecord::Migrator.run(:down, "db/migrate/", version)
174
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
175
+ end
176
+
177
+ desc "Display status of migrations"
178
+ task :status => :environment do
179
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
180
+ ActiveRecord::Base.establish_connection(config)
181
+ unless ActiveRecord::Base.connection.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name)
182
+ puts 'Schema migrations table does not exist yet.'
183
+ next # means "return" for rake task
184
+ end
185
+ db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}")
186
+ file_list = []
187
+ Dir.foreach(File.join(Rails.root, 'db', 'migrate')) do |file|
188
+ # only files matching "20091231235959_some_name.rb" pattern
189
+ if match_data = /(\d{14})_(.+)\.rb/.match(file)
190
+ status = db_list.delete(match_data[1]) ? 'up' : 'down'
191
+ file_list << [status, match_data[1], match_data[2]]
192
+ end
193
+ end
194
+ # output
195
+ puts "\ndatabase: #{config['database']}\n\n"
196
+ puts "#{"Status".center(8)} #{"Migration ID".ljust(14)} Migration Name"
197
+ puts "-" * 50
198
+ file_list.each do |file|
199
+ puts "#{file[0].center(8)} #{file[1].ljust(14)} #{file[2].humanize}"
200
+ end
201
+ db_list.each do |version|
202
+ puts "#{'up'.center(8)} #{version.ljust(14)} *** NO FILE ***"
203
+ end
204
+ puts
205
+ end
206
+ end
207
+
208
+ desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
209
+ task :rollback => :environment do
210
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
211
+ ActiveRecord::Migrator.rollback('db/migrate/', step)
212
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
213
+ end
214
+
215
+ # desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
216
+ task :forward => :environment do
217
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
218
+ ActiveRecord::Migrator.forward('db/migrate/', step)
219
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
220
+ end
221
+
222
+ # desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
223
+ task :reset => [ 'db:drop', 'db:setup' ]
224
+
225
+ # desc "Retrieves the charset for the current environment's database"
226
+ task :charset => :environment do
227
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
228
+ case config['adapter']
229
+ when /mysql/
230
+ ActiveRecord::Base.establish_connection(config)
231
+ puts ActiveRecord::Base.connection.charset
232
+ when 'postgresql'
233
+ ActiveRecord::Base.establish_connection(config)
234
+ puts ActiveRecord::Base.connection.encoding
235
+ when 'sqlite3'
236
+ ActiveRecord::Base.establish_connection(config)
237
+ puts ActiveRecord::Base.connection.encoding
238
+ else
239
+ $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
240
+ end
241
+ end
242
+
243
+ # desc "Retrieves the collation for the current environment's database"
244
+ task :collation => :environment do
245
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
246
+ case config['adapter']
247
+ when /mysql/
248
+ ActiveRecord::Base.establish_connection(config)
249
+ puts ActiveRecord::Base.connection.collation
250
+ else
251
+ $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
252
+ end
253
+ end
254
+
255
+ desc "Retrieves the current schema version number"
256
+ task :version => :environment do
257
+ puts "Current version: #{ActiveRecord::Migrator.current_version}"
258
+ end
259
+
260
+ # desc "Raises an error if there are pending migrations"
261
+ task :abort_if_pending_migrations => :environment do
262
+ if defined? ActiveRecord
263
+ pending_migrations = ActiveRecord::Migrator.new(:up, 'db/migrate').pending_migrations
264
+
265
+ if pending_migrations.any?
266
+ puts "You have #{pending_migrations.size} pending migrations:"
267
+ pending_migrations.each do |pending_migration|
268
+ puts ' %4d %s' % [pending_migration.version, pending_migration.name]
269
+ end
270
+ abort %{Run "rake db:migrate" to update your database then try again.}
271
+ end
272
+ end
273
+ end
274
+
275
+ desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)'
276
+ task :setup => [ 'db:create', 'db:schema:load', 'db:seed' ]
277
+
278
+ desc 'Load the seed data from db/seeds.rb'
279
+ task :seed => 'db:abort_if_pending_migrations' do
280
+ seed_file = File.join(Rails.root, 'db', 'seeds.rb')
281
+ load(seed_file) if File.exist?(seed_file)
282
+ end
283
+
284
+ namespace :fixtures do
285
+ 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."
286
+ task :load => :environment do
287
+ require 'active_record/fixtures'
288
+
289
+ ActiveRecord::Base.establish_connection(Rails.env)
290
+ base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures')
291
+ fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir
292
+
293
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir["#{fixtures_dir}/**/*.{yml,csv}"]).each do |fixture_file|
294
+ Fixtures.create_fixtures(fixtures_dir, fixture_file[(fixtures_dir.size + 1)..-5])
295
+ end
296
+ end
297
+
298
+ # desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
299
+ task :identify => :environment do
300
+ require 'active_record/fixtures'
301
+
302
+ label, id = ENV["LABEL"], ENV["ID"]
303
+ raise "LABEL or ID required" if label.blank? && id.blank?
304
+
305
+ puts %Q(The fixture ID for "#{label}" is #{Fixtures.identify(label)}.) if label
306
+
307
+ base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures')
308
+ Dir["#{base_dir}/**/*.yml"].each do |file|
309
+ if data = YAML::load(ERB.new(IO.read(file)).result)
310
+ data.keys.each do |key|
311
+ key_id = Fixtures.identify(key)
312
+
313
+ if key == label || key_id == id.to_i
314
+ puts "#{file}: #{key} (#{key_id})"
315
+ end
316
+ end
317
+ end
318
+ end
319
+ end
320
+ end
321
+
322
+ namespace :schema do
323
+ desc "Create a db/schema.rb file that can be portably used against any DB supported by AR"
324
+ task :dump => :environment do
325
+ require 'active_record/schema_dumper'
326
+ File.open(ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb", "w") do |file|
327
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
328
+ end
329
+ Rake::Task["db:schema:dump"].reenable
330
+ end
331
+
332
+ desc "Load a schema.rb file into the database"
333
+ task :load => :environment do
334
+ file = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
335
+ if File.exists?(file)
336
+ load(file)
337
+ else
338
+ 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/boot.rb to limit the frameworks that will be loaded}
339
+ end
340
+ end
341
+ end
342
+
343
+ namespace :structure do
344
+ desc "Dump the database structure to an SQL file"
345
+ task :dump => :environment do
346
+ abcs = ActiveRecord::Base.configurations
347
+ case abcs[Rails.env]["adapter"]
348
+ when /mysql/, "oci", "oracle"
349
+ ActiveRecord::Base.establish_connection(abcs[Rails.env])
350
+ File.open("#{Rails.root}/db/#{Rails.env}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
351
+ when "postgresql"
352
+ ENV['PGHOST'] = abcs[Rails.env]["host"] if abcs[Rails.env]["host"]
353
+ ENV['PGPORT'] = abcs[Rails.env]["port"].to_s if abcs[Rails.env]["port"]
354
+ ENV['PGPASSWORD'] = abcs[Rails.env]["password"].to_s if abcs[Rails.env]["password"]
355
+ search_path = abcs[Rails.env]["schema_search_path"]
356
+ unless search_path.blank?
357
+ search_path = search_path.split(",").map{|search_path| "--schema=#{search_path.strip}" }.join(" ")
358
+ end
359
+ `pg_dump -i -U "#{abcs[Rails.env]["username"]}" -s -x -O -f db/#{Rails.env}_structure.sql #{search_path} #{abcs[Rails.env]["database"]}`
360
+ raise "Error dumping database" if $?.exitstatus == 1
361
+ when "sqlite", "sqlite3"
362
+ dbfile = abcs[Rails.env]["database"] || abcs[Rails.env]["dbfile"]
363
+ `#{abcs[Rails.env]["adapter"]} #{dbfile} .schema > db/#{Rails.env}_structure.sql`
364
+ when "sqlserver"
365
+ `scptxfr /s #{abcs[Rails.env]["host"]} /d #{abcs[Rails.env]["database"]} /I /f db\\#{Rails.env}_structure.sql /q /A /r`
366
+ `scptxfr /s #{abcs[Rails.env]["host"]} /d #{abcs[Rails.env]["database"]} /I /F db\ /q /A /r`
367
+ when "firebird"
368
+ set_firebird_env(abcs[Rails.env])
369
+ db_string = firebird_db_string(abcs[Rails.env])
370
+ sh "isql -a #{db_string} > #{Rails.root}/db/#{Rails.env}_structure.sql"
371
+ else
372
+ raise "Task not supported by '#{abcs["test"]["adapter"]}'"
373
+ end
374
+
375
+ if ActiveRecord::Base.connection.supports_migrations?
376
+ File.open("#{Rails.root}/db/#{Rails.env}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
377
+ end
378
+ end
379
+ end
380
+
381
+ namespace :test do
382
+ # desc "Recreate the test database from the current schema.rb"
383
+ task :load => 'db:test:purge' do
384
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
385
+ ActiveRecord::Schema.verbose = false
386
+ Rake::Task["db:schema:load"].invoke
387
+ end
388
+
389
+ # desc "Recreate the test database from the current environment's database schema"
390
+ task :clone => %w(db:schema:dump db:test:load)
391
+
392
+ # desc "Recreate the test databases from the development structure"
393
+ task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
394
+ abcs = ActiveRecord::Base.configurations
395
+ case abcs["test"]["adapter"]
396
+ when /mysql/
397
+ ActiveRecord::Base.establish_connection(:test)
398
+ ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
399
+ IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split("\n\n").each do |table|
400
+ ActiveRecord::Base.connection.execute(table)
401
+ end
402
+ when "postgresql"
403
+ ENV['PGHOST'] = abcs["test"]["host"] if abcs["test"]["host"]
404
+ ENV['PGPORT'] = abcs["test"]["port"].to_s if abcs["test"]["port"]
405
+ ENV['PGPASSWORD'] = abcs["test"]["password"].to_s if abcs["test"]["password"]
406
+ `psql -U "#{abcs["test"]["username"]}" -f #{Rails.root}/db/#{Rails.env}_structure.sql #{abcs["test"]["database"]}`
407
+ when "sqlite", "sqlite3"
408
+ dbfile = abcs["test"]["database"] || abcs["test"]["dbfile"]
409
+ `#{abcs["test"]["adapter"]} #{dbfile} < #{Rails.root}/db/#{Rails.env}_structure.sql`
410
+ when "sqlserver"
411
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{Rails.env}_structure.sql`
412
+ when "oci", "oracle"
413
+ ActiveRecord::Base.establish_connection(:test)
414
+ IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split(";\n\n").each do |ddl|
415
+ ActiveRecord::Base.connection.execute(ddl)
416
+ end
417
+ when "firebird"
418
+ set_firebird_env(abcs["test"])
419
+ db_string = firebird_db_string(abcs["test"])
420
+ sh "isql -i #{Rails.root}/db/#{Rails.env}_structure.sql #{db_string}"
421
+ else
422
+ raise "Task not supported by '#{abcs["test"]["adapter"]}'"
423
+ end
424
+ end
425
+
426
+ # desc "Empty the test database"
427
+ task :purge => :environment do
428
+ abcs = ActiveRecord::Base.configurations
429
+ case abcs["test"]["adapter"]
430
+ when /mysql/
431
+ ActiveRecord::Base.establish_connection(:test)
432
+ ActiveRecord::Base.connection.recreate_database(abcs["test"]["database"], abcs["test"])
433
+ when "postgresql"
434
+ ActiveRecord::Base.clear_active_connections!
435
+ drop_database(abcs['test'])
436
+ create_database(abcs['test'])
437
+ when "sqlite","sqlite3"
438
+ dbfile = abcs["test"]["database"] || abcs["test"]["dbfile"]
439
+ File.delete(dbfile) if File.exist?(dbfile)
440
+ when "sqlserver"
441
+ dropfkscript = "#{abcs["test"]["host"]}.#{abcs["test"]["database"]}.DP1".gsub(/\\/,'-')
442
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{dropfkscript}`
443
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{Rails.env}_structure.sql`
444
+ when "oci", "oracle"
445
+ ActiveRecord::Base.establish_connection(:test)
446
+ ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
447
+ ActiveRecord::Base.connection.execute(ddl)
448
+ end
449
+ when "firebird"
450
+ ActiveRecord::Base.establish_connection(:test)
451
+ ActiveRecord::Base.connection.recreate_database!
452
+ else
453
+ raise "Task not supported by '#{abcs["test"]["adapter"]}'"
454
+ end
455
+ end
456
+
457
+ # desc 'Check for pending migrations and load the test schema'
458
+ task :prepare => 'db:abort_if_pending_migrations' do
459
+ if defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
460
+ Rake::Task[{ :sql => "db:test:clone_structure", :ruby => "db:test:load" }[ActiveRecord::Base.schema_format]].invoke
461
+ end
462
+ end
463
+ end
464
+
465
+ namespace :sessions do
466
+ # desc "Creates a sessions migration for use with ActiveRecord::SessionStore"
467
+ task :create => :environment do
468
+ raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations?
469
+ require 'rails/generators'
470
+ Rails::Generators.configure!
471
+ require 'rails/generators/rails/session_migration/session_migration_generator'
472
+ Rails::Generators::SessionMigrationGenerator.start [ ENV["MIGRATION"] || "add_sessions_table" ]
473
+ end
474
+
475
+ # desc "Clear the sessions table"
476
+ task :clear => :environment do
477
+ ActiveRecord::Base.connection.execute "DELETE FROM #{session_table_name}"
478
+ end
479
+ end
480
+ end
481
+
482
+ task 'test:prepare' => 'db:test:prepare'
483
+
484
+ def drop_database(config)
485
+ case config['adapter']
486
+ when /mysql/
487
+ ActiveRecord::Base.establish_connection(config)
488
+ ActiveRecord::Base.connection.drop_database config['database']
489
+ when /^sqlite/
490
+ require 'pathname'
491
+ path = Pathname.new(config['database'])
492
+ file = path.absolute? ? path.to_s : File.join(Rails.root, path)
493
+
494
+ FileUtils.rm(file)
495
+ when 'postgresql'
496
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
497
+ ActiveRecord::Base.connection.drop_database config['database']
498
+ end
499
+ end
500
+
501
+ def session_table_name
502
+ ActiveRecord::SessionStore::Session.table_name
503
+ end
504
+
505
+ def set_firebird_env(config)
506
+ ENV["ISC_USER"] = config["username"].to_s if config["username"]
507
+ ENV["ISC_PASSWORD"] = config["password"].to_s if config["password"]
508
+ end
509
+
510
+ def firebird_db_string(config)
511
+ FireRuby::Database.db_string_for(config.symbolize_keys)
512
+ end