square-activerecord 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/CHANGELOG +6140 -0
  2. data/README.rdoc +222 -0
  3. data/examples/associations.png +0 -0
  4. data/examples/performance.rb +179 -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 +430 -0
  9. data/lib/active_record/associations.rb +2307 -0
  10. data/lib/active_record/associations/association_collection.rb +572 -0
  11. data/lib/active_record/associations/association_proxy.rb +299 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +91 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +82 -0
  14. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
  15. data/lib/active_record/associations/has_many_association.rb +128 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +115 -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 +30 -0
  22. data/lib/active_record/attribute_methods/dirty.rb +95 -0
  23. data/lib/active_record/attribute_methods/primary_key.rb +56 -0
  24. data/lib/active_record/attribute_methods/query.rb +39 -0
  25. data/lib/active_record/attribute_methods/read.rb +145 -0
  26. data/lib/active_record/attribute_methods/time_zone_conversion.rb +64 -0
  27. data/lib/active_record/attribute_methods/write.rb +43 -0
  28. data/lib/active_record/autosave_association.rb +369 -0
  29. data/lib/active_record/base.rb +1904 -0
  30. data/lib/active_record/callbacks.rb +284 -0
  31. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +364 -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 +333 -0
  35. data/lib/active_record/connection_adapters/abstract/query_cache.rb +81 -0
  36. data/lib/active_record/connection_adapters/abstract/quoting.rb +73 -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 +539 -0
  39. data/lib/active_record/connection_adapters/abstract_adapter.rb +217 -0
  40. data/lib/active_record/connection_adapters/mysql_adapter.rb +657 -0
  41. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1031 -0
  42. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -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 +56 -0
  46. data/lib/active_record/dynamic_scope_match.rb +23 -0
  47. data/lib/active_record/errors.rb +172 -0
  48. data/lib/active_record/fixtures.rb +1006 -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 +419 -0
  56. data/lib/active_record/observer.rb +125 -0
  57. data/lib/active_record/persistence.rb +290 -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 +411 -0
  63. data/lib/active_record/relation.rb +394 -0
  64. data/lib/active_record/relation/batches.rb +89 -0
  65. data/lib/active_record/relation/calculations.rb +295 -0
  66. data/lib/active_record/relation/finder_methods.rb +363 -0
  67. data/lib/active_record/relation/predicate_builder.rb +48 -0
  68. data/lib/active_record/relation/query_methods.rb +303 -0
  69. data/lib/active_record/relation/spawn_methods.rb +132 -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 +359 -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 +190 -0
  81. data/lib/active_record/version.rb +10 -0
  82. data/lib/rails/generators/active_record.rb +19 -0
  83. data/lib/rails/generators/active_record/migration.rb +15 -0
  84. data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
  85. data/lib/rails/generators/active_record/migration/templates/migration.rb +17 -0
  86. data/lib/rails/generators/active_record/model/model_generator.rb +38 -0
  87. data/lib/rails/generators/active_record/model/templates/migration.rb +16 -0
  88. data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
  89. data/lib/rails/generators/active_record/model/templates/module.rb +5 -0
  90. data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
  91. data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
  92. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +24 -0
  93. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +16 -0
  94. metadata +223 -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 Exception => e
49
+ $stderr.puts e, *(e.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 Exception => e
95
+ $stderr.puts e, *(e.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/application.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[Rails.env]["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