activerecord 3.0.20 → 3.1.0.beta1
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.
- data/CHANGELOG +220 -91
- data/README.rdoc +3 -3
- data/examples/performance.rb +88 -109
- data/lib/active_record.rb +6 -2
- data/lib/active_record/aggregations.rb +22 -45
- data/lib/active_record/associations.rb +264 -991
- data/lib/active_record/associations/alias_tracker.rb +85 -0
- data/lib/active_record/associations/association.rb +231 -0
- data/lib/active_record/associations/association_scope.rb +120 -0
- data/lib/active_record/associations/belongs_to_association.rb +40 -60
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +15 -63
- data/lib/active_record/associations/builder/association.rb +53 -0
- data/lib/active_record/associations/builder/belongs_to.rb +85 -0
- data/lib/active_record/associations/builder/collection_association.rb +75 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +63 -0
- data/lib/active_record/associations/builder/has_many.rb +65 -0
- data/lib/active_record/associations/builder/has_one.rb +63 -0
- data/lib/active_record/associations/builder/singular_association.rb +32 -0
- data/lib/active_record/associations/collection_association.rb +524 -0
- data/lib/active_record/associations/collection_proxy.rb +125 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +27 -118
- data/lib/active_record/associations/has_many_association.rb +50 -79
- data/lib/active_record/associations/has_many_through_association.rb +98 -67
- data/lib/active_record/associations/has_one_association.rb +45 -115
- data/lib/active_record/associations/has_one_through_association.rb +21 -25
- data/lib/active_record/associations/join_dependency.rb +215 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +150 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
- data/lib/active_record/associations/join_helper.rb +56 -0
- data/lib/active_record/associations/preloader.rb +177 -0
- data/lib/active_record/associations/preloader/association.rb +126 -0
- data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
- data/lib/active_record/associations/preloader/collection_association.rb +24 -0
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
- data/lib/active_record/associations/preloader/has_many.rb +17 -0
- data/lib/active_record/associations/preloader/has_many_through.rb +15 -0
- data/lib/active_record/associations/preloader/has_one.rb +23 -0
- data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
- data/lib/active_record/associations/preloader/singular_association.rb +21 -0
- data/lib/active_record/associations/preloader/through_association.rb +67 -0
- data/lib/active_record/associations/singular_association.rb +55 -0
- data/lib/active_record/associations/through_association.rb +80 -0
- data/lib/active_record/attribute_methods.rb +19 -5
- data/lib/active_record/attribute_methods/before_type_cast.rb +9 -8
- data/lib/active_record/attribute_methods/dirty.rb +8 -2
- data/lib/active_record/attribute_methods/primary_key.rb +33 -13
- data/lib/active_record/attribute_methods/read.rb +17 -17
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +7 -4
- data/lib/active_record/attribute_methods/write.rb +2 -1
- data/lib/active_record/autosave_association.rb +66 -45
- data/lib/active_record/base.rb +445 -273
- data/lib/active_record/callbacks.rb +24 -33
- data/lib/active_record/coders/yaml_column.rb +41 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +106 -13
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +16 -2
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +12 -11
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -12
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +16 -16
- data/lib/active_record/connection_adapters/abstract/quoting.rb +61 -22
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +16 -273
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +80 -42
- data/lib/active_record/connection_adapters/abstract_adapter.rb +44 -25
- data/lib/active_record/connection_adapters/column.rb +268 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +686 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +331 -88
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +295 -267
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +3 -7
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +108 -26
- data/lib/active_record/counter_cache.rb +7 -4
- data/lib/active_record/fixtures.rb +174 -192
- data/lib/active_record/identity_map.rb +131 -0
- data/lib/active_record/locking/optimistic.rb +20 -14
- data/lib/active_record/locking/pessimistic.rb +4 -4
- data/lib/active_record/log_subscriber.rb +24 -4
- data/lib/active_record/migration.rb +265 -144
- data/lib/active_record/migration/command_recorder.rb +103 -0
- data/lib/active_record/named_scope.rb +68 -25
- data/lib/active_record/nested_attributes.rb +58 -15
- data/lib/active_record/observer.rb +3 -7
- data/lib/active_record/persistence.rb +58 -38
- data/lib/active_record/query_cache.rb +25 -3
- data/lib/active_record/railtie.rb +21 -12
- data/lib/active_record/railties/console_sandbox.rb +6 -0
- data/lib/active_record/railties/databases.rake +147 -116
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/reflection.rb +176 -44
- data/lib/active_record/relation.rb +125 -49
- data/lib/active_record/relation/batches.rb +7 -5
- data/lib/active_record/relation/calculations.rb +50 -18
- data/lib/active_record/relation/finder_methods.rb +47 -26
- data/lib/active_record/relation/predicate_builder.rb +24 -21
- data/lib/active_record/relation/query_methods.rb +117 -101
- data/lib/active_record/relation/spawn_methods.rb +27 -20
- data/lib/active_record/result.rb +34 -0
- data/lib/active_record/schema.rb +5 -6
- data/lib/active_record/schema_dumper.rb +11 -13
- data/lib/active_record/serialization.rb +2 -2
- data/lib/active_record/serializers/xml_serializer.rb +10 -10
- data/lib/active_record/session_store.rb +8 -2
- data/lib/active_record/test_case.rb +9 -20
- data/lib/active_record/timestamp.rb +21 -9
- data/lib/active_record/transactions.rb +16 -15
- data/lib/active_record/validations.rb +21 -22
- data/lib/active_record/validations/associated.rb +3 -1
- data/lib/active_record/validations/uniqueness.rb +48 -58
- data/lib/active_record/version.rb +3 -3
- data/lib/rails/generators/active_record.rb +6 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +10 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +2 -1
- data/lib/rails/generators/active_record/model/templates/migration.rb +6 -5
- data/lib/rails/generators/active_record/model/templates/model.rb +2 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +2 -0
- data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +2 -1
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +2 -2
- metadata +106 -77
- checksums.yaml +0 -7
- data/lib/active_record/association_preload.rb +0 -431
- data/lib/active_record/associations/association_collection.rb +0 -572
- data/lib/active_record/associations/association_proxy.rb +0 -304
- data/lib/active_record/associations/through_association_scope.rb +0 -160
@@ -27,10 +27,32 @@ module ActiveRecord
|
|
27
27
|
@app = app
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
@
|
30
|
+
class BodyProxy # :nodoc:
|
31
|
+
def initialize(original_cache_value, target)
|
32
|
+
@original_cache_value = original_cache_value
|
33
|
+
@target = target
|
34
|
+
end
|
35
|
+
|
36
|
+
def each(&block)
|
37
|
+
@target.each(&block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def close
|
41
|
+
@target.close if @target.respond_to?(:close)
|
42
|
+
ensure
|
43
|
+
ActiveRecord::Base.connection.clear_query_cache
|
44
|
+
unless @original_cache_value
|
45
|
+
ActiveRecord::Base.connection.disable_query_cache!
|
46
|
+
end
|
33
47
|
end
|
34
48
|
end
|
49
|
+
|
50
|
+
def call(env)
|
51
|
+
old = ActiveRecord::Base.connection.query_cache_enabled
|
52
|
+
ActiveRecord::Base.connection.enable_query_cache!
|
53
|
+
|
54
|
+
status, headers, body = @app.call(env)
|
55
|
+
[status, headers, BodyProxy.new(old, body)]
|
56
|
+
end
|
35
57
|
end
|
36
58
|
end
|
@@ -13,8 +13,8 @@ module ActiveRecord
|
|
13
13
|
class Railtie < Rails::Railtie
|
14
14
|
config.active_record = ActiveSupport::OrderedOptions.new
|
15
15
|
|
16
|
-
config.
|
17
|
-
|
16
|
+
config.app_generators.orm :active_record, :migration => true,
|
17
|
+
:timestamps => true
|
18
18
|
|
19
19
|
config.app_middleware.insert_after "::ActionDispatch::Callbacks",
|
20
20
|
"ActiveRecord::QueryCache"
|
@@ -26,10 +26,12 @@ module ActiveRecord
|
|
26
26
|
load "active_record/railties/databases.rake"
|
27
27
|
end
|
28
28
|
|
29
|
-
# When loading console, force ActiveRecord to be loaded
|
30
|
-
# references when loading a constant for the
|
31
|
-
|
32
|
-
|
29
|
+
# When loading console, force ActiveRecord::Base to be loaded
|
30
|
+
# to avoid cross references when loading a constant for the
|
31
|
+
# first time. Also, make it output to STDERR.
|
32
|
+
console do |sandbox|
|
33
|
+
require "active_record/railties/console_sandbox" if sandbox
|
34
|
+
ActiveRecord::Base.logger = Logger.new(STDERR)
|
33
35
|
end
|
34
36
|
|
35
37
|
initializer "active_record.initialize_timezone" do
|
@@ -43,8 +45,16 @@ module ActiveRecord
|
|
43
45
|
ActiveSupport.on_load(:active_record) { self.logger ||= ::Rails.logger }
|
44
46
|
end
|
45
47
|
|
48
|
+
initializer "active_record.identity_map" do |app|
|
49
|
+
config.app_middleware.insert_after "::ActionDispatch::Callbacks",
|
50
|
+
"ActiveRecord::IdentityMap::Middleware" if config.active_record.delete(:identity_map)
|
51
|
+
end
|
52
|
+
|
46
53
|
initializer "active_record.set_configs" do |app|
|
47
54
|
ActiveSupport.on_load(:active_record) do
|
55
|
+
if app.config.active_record.delete(:whitelist_attributes)
|
56
|
+
attr_accessible(nil)
|
57
|
+
end
|
48
58
|
app.config.active_record.each do |k,v|
|
49
59
|
send "#{k}=", v
|
50
60
|
end
|
@@ -69,11 +79,10 @@ module ActiveRecord
|
|
69
79
|
end
|
70
80
|
|
71
81
|
initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
82
|
+
ActiveSupport.on_load(:active_record) do
|
83
|
+
ActionDispatch::Reloader.to_cleanup do
|
84
|
+
ActiveRecord::Base.clear_reloadable_connections!
|
85
|
+
ActiveRecord::Base.clear_cache!
|
77
86
|
end
|
78
87
|
end
|
79
88
|
end
|
@@ -82,7 +91,7 @@ module ActiveRecord
|
|
82
91
|
ActiveSupport.on_load(:active_record) do
|
83
92
|
instantiate_observers
|
84
93
|
|
85
|
-
ActionDispatch::
|
94
|
+
ActionDispatch::Reloader.to_prepare do
|
86
95
|
ActiveRecord::Base.instantiate_observers
|
87
96
|
end
|
88
97
|
end
|
@@ -1,7 +1,16 @@
|
|
1
|
-
|
1
|
+
require 'active_support/core_ext/object/inclusion'
|
2
|
+
|
3
|
+
db_namespace = namespace :db do
|
2
4
|
task :load_config => :rails_env do
|
3
5
|
require 'active_record'
|
4
6
|
ActiveRecord::Base.configurations = Rails.application.config.database_configuration
|
7
|
+
ActiveRecord::Migrator.migrations_paths = Rails.application.paths['db/migrate'].to_a
|
8
|
+
|
9
|
+
if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
|
10
|
+
if engine.paths['db/migrate'].existent
|
11
|
+
ActiveRecord::Migrator.migrations_paths += engine.paths['db/migrate'].to_a
|
12
|
+
end
|
13
|
+
end
|
5
14
|
end
|
6
15
|
|
7
16
|
namespace :create do
|
@@ -35,12 +44,6 @@ namespace :db do
|
|
35
44
|
create_database(ActiveRecord::Base.configurations[Rails.env])
|
36
45
|
end
|
37
46
|
|
38
|
-
def mysql_creation_options(config)
|
39
|
-
@charset = ENV['CHARSET'] || 'utf8'
|
40
|
-
@collation = ENV['COLLATION'] || 'utf8_unicode_ci'
|
41
|
-
{:charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation)}
|
42
|
-
end
|
43
|
-
|
44
47
|
def create_database(config)
|
45
48
|
begin
|
46
49
|
if config['adapter'] =~ /sqlite/
|
@@ -63,7 +66,10 @@ namespace :db do
|
|
63
66
|
end
|
64
67
|
rescue
|
65
68
|
case config['adapter']
|
66
|
-
when
|
69
|
+
when /mysql/
|
70
|
+
@charset = ENV['CHARSET'] || 'utf8'
|
71
|
+
@collation = ENV['COLLATION'] || 'utf8_unicode_ci'
|
72
|
+
creation_options = {:charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation)}
|
67
73
|
if config['adapter'] =~ /jdbc/
|
68
74
|
#FIXME After Jdbcmysql gives this class
|
69
75
|
require 'active_record/railties/jdbcmysql_error'
|
@@ -74,7 +80,7 @@ namespace :db do
|
|
74
80
|
access_denied_error = 1045
|
75
81
|
begin
|
76
82
|
ActiveRecord::Base.establish_connection(config.merge('database' => nil))
|
77
|
-
ActiveRecord::Base.connection.create_database(config['database'],
|
83
|
+
ActiveRecord::Base.connection.create_database(config['database'], creation_options)
|
78
84
|
ActiveRecord::Base.establish_connection(config)
|
79
85
|
rescue error_class => sqlerr
|
80
86
|
if sqlerr.errno == access_denied_error
|
@@ -85,7 +91,7 @@ namespace :db do
|
|
85
91
|
"IDENTIFIED BY '#{config['password']}' WITH GRANT OPTION;"
|
86
92
|
ActiveRecord::Base.establish_connection(config.merge(
|
87
93
|
'database' => nil, 'username' => 'root', 'password' => root_password))
|
88
|
-
ActiveRecord::Base.connection.create_database(config['database'],
|
94
|
+
ActiveRecord::Base.connection.create_database(config['database'], creation_options)
|
89
95
|
ActiveRecord::Base.connection.execute grant_statement
|
90
96
|
ActiveRecord::Base.establish_connection(config)
|
91
97
|
else
|
@@ -94,7 +100,7 @@ namespace :db do
|
|
94
100
|
$stderr.puts "(if you set the charset manually, make sure you have a matching collation)" if config['charset']
|
95
101
|
end
|
96
102
|
end
|
97
|
-
when
|
103
|
+
when /postgresql/
|
98
104
|
@encoding = config['encoding'] || ENV['CHARSET'] || 'utf8'
|
99
105
|
begin
|
100
106
|
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
|
@@ -137,7 +143,7 @@ namespace :db do
|
|
137
143
|
end
|
138
144
|
|
139
145
|
def local_database?(config, &block)
|
140
|
-
if
|
146
|
+
if config['host'].in?(['127.0.0.1', 'localhost']) || config['host'].blank?
|
141
147
|
yield
|
142
148
|
else
|
143
149
|
$stderr.puts "This task only modifies local databases. #{config['database']} is on a remote host."
|
@@ -146,45 +152,45 @@ namespace :db do
|
|
146
152
|
|
147
153
|
|
148
154
|
desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
|
149
|
-
task :migrate => :environment do
|
155
|
+
task :migrate => [:environment, :load_config] do
|
150
156
|
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
151
|
-
ActiveRecord::Migrator.migrate(
|
152
|
-
|
157
|
+
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
|
158
|
+
db_namespace["schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
|
153
159
|
end
|
154
160
|
|
155
161
|
namespace :migrate do
|
156
162
|
# desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
|
157
|
-
task :redo => :environment do
|
158
|
-
if ENV[
|
159
|
-
|
160
|
-
|
163
|
+
task :redo => [:environment, :load_config] do
|
164
|
+
if ENV['VERSION']
|
165
|
+
db_namespace['migrate:down'].invoke
|
166
|
+
db_namespace['migrate:up'].invoke
|
161
167
|
else
|
162
|
-
|
163
|
-
|
168
|
+
db_namespace['rollback'].invoke
|
169
|
+
db_namespace['migrate'].invoke
|
164
170
|
end
|
165
171
|
end
|
166
172
|
|
167
173
|
# desc 'Resets your database using your migrations for the current environment'
|
168
|
-
task :reset => [
|
174
|
+
task :reset => ['db:drop', 'db:create', 'db:migrate']
|
169
175
|
|
170
176
|
# desc 'Runs the "up" for a given migration VERSION.'
|
171
|
-
task :up => :environment do
|
172
|
-
version = ENV[
|
173
|
-
raise
|
174
|
-
ActiveRecord::Migrator.run(:up,
|
175
|
-
|
177
|
+
task :up => [:environment, :load_config] do
|
178
|
+
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
179
|
+
raise 'VERSION is required' unless version
|
180
|
+
ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
|
181
|
+
db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
|
176
182
|
end
|
177
183
|
|
178
184
|
# desc 'Runs the "down" for a given migration VERSION.'
|
179
|
-
task :down => :environment do
|
180
|
-
version = ENV[
|
181
|
-
raise
|
182
|
-
ActiveRecord::Migrator.run(:down,
|
183
|
-
|
185
|
+
task :down => [:environment, :load_config] do
|
186
|
+
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
187
|
+
raise 'VERSION is required' unless version
|
188
|
+
ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
|
189
|
+
db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
|
184
190
|
end
|
185
191
|
|
186
|
-
desc
|
187
|
-
task :status => :environment do
|
192
|
+
desc 'Display status of migrations'
|
193
|
+
task :status => [:environment, :load_config] do
|
188
194
|
config = ActiveRecord::Base.configurations[Rails.env || 'development']
|
189
195
|
ActiveRecord::Base.establish_connection(config)
|
190
196
|
unless ActiveRecord::Base.connection.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name)
|
@@ -195,14 +201,14 @@ namespace :db do
|
|
195
201
|
file_list = []
|
196
202
|
Dir.foreach(File.join(Rails.root, 'db', 'migrate')) do |file|
|
197
203
|
# only files matching "20091231235959_some_name.rb" pattern
|
198
|
-
if match_data =
|
204
|
+
if match_data = /^(\d{14})_(.+)\.rb$/.match(file)
|
199
205
|
status = db_list.delete(match_data[1]) ? 'up' : 'down'
|
200
206
|
file_list << [status, match_data[1], match_data[2]]
|
201
207
|
end
|
202
208
|
end
|
203
209
|
# output
|
204
210
|
puts "\ndatabase: #{config['database']}\n\n"
|
205
|
-
puts "#{
|
211
|
+
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
206
212
|
puts "-" * 50
|
207
213
|
file_list.each do |file|
|
208
214
|
puts "#{file[0].center(8)} #{file[1].ljust(14)} #{file[2].humanize}"
|
@@ -215,17 +221,17 @@ namespace :db do
|
|
215
221
|
end
|
216
222
|
|
217
223
|
desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
|
218
|
-
task :rollback => :environment do
|
224
|
+
task :rollback => [:environment, :load_config] do
|
219
225
|
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
220
|
-
ActiveRecord::Migrator.rollback(
|
221
|
-
|
226
|
+
ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
|
227
|
+
db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
|
222
228
|
end
|
223
229
|
|
224
230
|
# desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
|
225
|
-
task :forward => :environment do
|
231
|
+
task :forward => [:environment, :load_config] do
|
226
232
|
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
227
|
-
ActiveRecord::Migrator.forward(
|
228
|
-
|
233
|
+
ActiveRecord::Migrator.forward(ActiveRecord::Migrator.migrations_paths, step)
|
234
|
+
db_namespace['schema:dump'].invoke if ActiveRecord::Base.schema_format == :ruby
|
229
235
|
end
|
230
236
|
|
231
237
|
# desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
|
@@ -235,13 +241,13 @@ namespace :db do
|
|
235
241
|
task :charset => :environment do
|
236
242
|
config = ActiveRecord::Base.configurations[Rails.env || 'development']
|
237
243
|
case config['adapter']
|
238
|
-
when
|
244
|
+
when /mysql/
|
239
245
|
ActiveRecord::Base.establish_connection(config)
|
240
246
|
puts ActiveRecord::Base.connection.charset
|
241
|
-
when
|
247
|
+
when /postgresql/
|
242
248
|
ActiveRecord::Base.establish_connection(config)
|
243
249
|
puts ActiveRecord::Base.connection.encoding
|
244
|
-
when
|
250
|
+
when /sqlite/
|
245
251
|
ActiveRecord::Base.establish_connection(config)
|
246
252
|
puts ActiveRecord::Base.connection.encoding
|
247
253
|
else
|
@@ -253,7 +259,7 @@ namespace :db do
|
|
253
259
|
task :collation => :environment do
|
254
260
|
config = ActiveRecord::Base.configurations[Rails.env || 'development']
|
255
261
|
case config['adapter']
|
256
|
-
when
|
262
|
+
when /mysql/
|
257
263
|
ActiveRecord::Base.establish_connection(config)
|
258
264
|
puts ActiveRecord::Base.connection.collation
|
259
265
|
else
|
@@ -261,7 +267,7 @@ namespace :db do
|
|
261
267
|
end
|
262
268
|
end
|
263
269
|
|
264
|
-
desc
|
270
|
+
desc 'Retrieves the current schema version number'
|
265
271
|
task :version => :environment do
|
266
272
|
puts "Current version: #{ActiveRecord::Migrator.current_version}"
|
267
273
|
end
|
@@ -269,7 +275,7 @@ namespace :db do
|
|
269
275
|
# desc "Raises an error if there are pending migrations"
|
270
276
|
task :abort_if_pending_migrations => :environment do
|
271
277
|
if defined? ActiveRecord
|
272
|
-
pending_migrations = ActiveRecord::Migrator.new(:up,
|
278
|
+
pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_paths).pending_migrations
|
273
279
|
|
274
280
|
if pending_migrations.any?
|
275
281
|
puts "You have #{pending_migrations.size} pending migrations:"
|
@@ -286,8 +292,7 @@ namespace :db do
|
|
286
292
|
|
287
293
|
desc 'Load the seed data from db/seeds.rb'
|
288
294
|
task :seed => 'db:abort_if_pending_migrations' do
|
289
|
-
|
290
|
-
load(seed_file) if File.exist?(seed_file)
|
295
|
+
Rails.application.load_seed
|
291
296
|
end
|
292
297
|
|
293
298
|
namespace :fixtures do
|
@@ -296,11 +301,11 @@ namespace :db do
|
|
296
301
|
require 'active_record/fixtures'
|
297
302
|
|
298
303
|
ActiveRecord::Base.establish_connection(Rails.env)
|
299
|
-
base_dir
|
300
|
-
fixtures_dir =
|
304
|
+
base_dir = File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
|
305
|
+
fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact
|
301
306
|
|
302
|
-
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/)
|
303
|
-
Fixtures.create_fixtures(fixtures_dir, fixture_file
|
307
|
+
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir["#{fixtures_dir}/**/*.{yml,csv}"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file|
|
308
|
+
Fixtures.create_fixtures(fixtures_dir, fixture_file)
|
304
309
|
end
|
305
310
|
end
|
306
311
|
|
@@ -308,8 +313,8 @@ namespace :db do
|
|
308
313
|
task :identify => :environment do
|
309
314
|
require 'active_record/fixtures'
|
310
315
|
|
311
|
-
label, id = ENV[
|
312
|
-
raise
|
316
|
+
label, id = ENV['LABEL'], ENV['ID']
|
317
|
+
raise 'LABEL or ID required' if label.blank? && id.blank?
|
313
318
|
|
314
319
|
puts %Q(The fixture ID for "#{label}" is #{Fixtures.identify(label)}.) if label
|
315
320
|
|
@@ -329,18 +334,16 @@ namespace :db do
|
|
329
334
|
end
|
330
335
|
|
331
336
|
namespace :schema do
|
332
|
-
desc
|
333
|
-
task :dump => :
|
337
|
+
desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR'
|
338
|
+
task :dump => :load_config do
|
334
339
|
require 'active_record/schema_dumper'
|
335
|
-
|
336
|
-
File.open(filename, "w:utf-8") do |file|
|
337
|
-
ActiveRecord::Base.establish_connection(Rails.env)
|
340
|
+
File.open(ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb", "w") do |file|
|
338
341
|
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
|
339
342
|
end
|
340
|
-
|
343
|
+
db_namespace['schema:dump'].reenable
|
341
344
|
end
|
342
345
|
|
343
|
-
desc
|
346
|
+
desc 'Load a schema.rb file into the database'
|
344
347
|
task :load => :environment do
|
345
348
|
file = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
|
346
349
|
if File.exists?(file)
|
@@ -352,29 +355,29 @@ namespace :db do
|
|
352
355
|
end
|
353
356
|
|
354
357
|
namespace :structure do
|
355
|
-
desc
|
358
|
+
desc 'Dump the database structure to an SQL file'
|
356
359
|
task :dump => :environment do
|
357
360
|
abcs = ActiveRecord::Base.configurations
|
358
|
-
case abcs[Rails.env][
|
359
|
-
when
|
361
|
+
case abcs[Rails.env]['adapter']
|
362
|
+
when /mysql/, 'oci', 'oracle'
|
360
363
|
ActiveRecord::Base.establish_connection(abcs[Rails.env])
|
361
364
|
File.open("#{Rails.root}/db/#{Rails.env}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
|
362
|
-
when
|
363
|
-
ENV['PGHOST'] = abcs[Rails.env][
|
364
|
-
ENV['PGPORT'] = abcs[Rails.env]["port"].to_s if abcs[Rails.env][
|
365
|
-
ENV['PGPASSWORD'] = abcs[Rails.env][
|
366
|
-
search_path = abcs[Rails.env][
|
365
|
+
when /postgresql/
|
366
|
+
ENV['PGHOST'] = abcs[Rails.env]['host'] if abcs[Rails.env]['host']
|
367
|
+
ENV['PGPORT'] = abcs[Rails.env]["port"].to_s if abcs[Rails.env]['port']
|
368
|
+
ENV['PGPASSWORD'] = abcs[Rails.env]['password'].to_s if abcs[Rails.env]['password']
|
369
|
+
search_path = abcs[Rails.env]['schema_search_path']
|
367
370
|
unless search_path.blank?
|
368
371
|
search_path = search_path.split(",").map{|search_path| "--schema=#{search_path.strip}" }.join(" ")
|
369
372
|
end
|
370
|
-
`pg_dump -i -U "#{abcs[Rails.env][
|
371
|
-
raise
|
372
|
-
when
|
373
|
-
dbfile = abcs[Rails.env][
|
373
|
+
`pg_dump -i -U "#{abcs[Rails.env]['username']}" -s -x -O -f db/#{Rails.env}_structure.sql #{search_path} #{abcs[Rails.env]['database']}`
|
374
|
+
raise 'Error dumping database' if $?.exitstatus == 1
|
375
|
+
when /sqlite/
|
376
|
+
dbfile = abcs[Rails.env]['database'] || abcs[Rails.env]['dbfile']
|
374
377
|
`sqlite3 #{dbfile} .schema > db/#{Rails.env}_structure.sql`
|
375
|
-
when
|
376
|
-
`scptxfr /s #{abcs[Rails.env][
|
377
|
-
`scptxfr /s #{abcs[Rails.env][
|
378
|
+
when 'sqlserver'
|
379
|
+
`scptxfr /s #{abcs[Rails.env]['host']} /d #{abcs[Rails.env]['database']} /I /f db\\#{Rails.env}_structure.sql /q /A /r`
|
380
|
+
`scptxfr /s #{abcs[Rails.env]['host']} /d #{abcs[Rails.env]['database']} /I /F db\ /q /A /r`
|
378
381
|
when "firebird"
|
379
382
|
set_firebird_env(abcs[Rails.env])
|
380
383
|
db_string = firebird_db_string(abcs[Rails.env])
|
@@ -394,81 +397,81 @@ namespace :db do
|
|
394
397
|
task :load => 'db:test:purge' do
|
395
398
|
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
|
396
399
|
ActiveRecord::Schema.verbose = false
|
397
|
-
|
400
|
+
db_namespace['schema:load'].invoke
|
398
401
|
end
|
399
402
|
|
400
403
|
# desc "Recreate the test database from the current environment's database schema"
|
401
404
|
task :clone => %w(db:schema:dump db:test:load)
|
402
405
|
|
403
406
|
# desc "Recreate the test databases from the development structure"
|
404
|
-
task :clone_structure => [
|
407
|
+
task :clone_structure => [ 'db:structure:dump', 'db:test:purge' ] do
|
405
408
|
abcs = ActiveRecord::Base.configurations
|
406
|
-
case abcs[
|
407
|
-
when
|
409
|
+
case abcs['test']['adapter']
|
410
|
+
when /mysql/
|
408
411
|
ActiveRecord::Base.establish_connection(:test)
|
409
412
|
ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
|
410
413
|
IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split("\n\n").each do |table|
|
411
414
|
ActiveRecord::Base.connection.execute(table)
|
412
415
|
end
|
413
|
-
when
|
414
|
-
ENV['PGHOST'] = abcs[
|
415
|
-
ENV['PGPORT'] = abcs[
|
416
|
-
ENV['PGPASSWORD'] = abcs[
|
417
|
-
`psql -U "#{abcs[
|
418
|
-
when
|
419
|
-
dbfile = abcs[
|
416
|
+
when /postgresql/
|
417
|
+
ENV['PGHOST'] = abcs['test']['host'] if abcs['test']['host']
|
418
|
+
ENV['PGPORT'] = abcs['test']['port'].to_s if abcs['test']['port']
|
419
|
+
ENV['PGPASSWORD'] = abcs['test']['password'].to_s if abcs['test']['password']
|
420
|
+
`psql -U "#{abcs['test']['username']}" -f #{Rails.root}/db/#{Rails.env}_structure.sql #{abcs['test']['database']} #{abcs['test']['template']}`
|
421
|
+
when /sqlite/
|
422
|
+
dbfile = abcs['test']['database'] || abcs['test']['dbfile']
|
420
423
|
`sqlite3 #{dbfile} < #{Rails.root}/db/#{Rails.env}_structure.sql`
|
421
|
-
when
|
422
|
-
`osql -E -S #{abcs[
|
423
|
-
when
|
424
|
+
when 'sqlserver'
|
425
|
+
`osql -E -S #{abcs['test']['host']} -d #{abcs['test']['database']} -i db\\#{Rails.env}_structure.sql`
|
426
|
+
when 'oci', 'oracle'
|
424
427
|
ActiveRecord::Base.establish_connection(:test)
|
425
428
|
IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split(";\n\n").each do |ddl|
|
426
429
|
ActiveRecord::Base.connection.execute(ddl)
|
427
430
|
end
|
428
|
-
when
|
429
|
-
set_firebird_env(abcs[
|
430
|
-
db_string = firebird_db_string(abcs[
|
431
|
+
when 'firebird'
|
432
|
+
set_firebird_env(abcs['test'])
|
433
|
+
db_string = firebird_db_string(abcs['test'])
|
431
434
|
sh "isql -i #{Rails.root}/db/#{Rails.env}_structure.sql #{db_string}"
|
432
435
|
else
|
433
|
-
raise "Task not supported by '#{abcs[
|
436
|
+
raise "Task not supported by '#{abcs['test']['adapter']}'"
|
434
437
|
end
|
435
438
|
end
|
436
439
|
|
437
440
|
# desc "Empty the test database"
|
438
441
|
task :purge => :environment do
|
439
442
|
abcs = ActiveRecord::Base.configurations
|
440
|
-
case abcs[
|
441
|
-
when
|
443
|
+
case abcs['test']['adapter']
|
444
|
+
when /mysql/
|
442
445
|
ActiveRecord::Base.establish_connection(:test)
|
443
|
-
ActiveRecord::Base.connection.recreate_database(abcs[
|
444
|
-
when
|
446
|
+
ActiveRecord::Base.connection.recreate_database(abcs['test']['database'], abcs['test'])
|
447
|
+
when /postgresql/
|
445
448
|
ActiveRecord::Base.clear_active_connections!
|
446
449
|
drop_database(abcs['test'])
|
447
450
|
create_database(abcs['test'])
|
448
|
-
when
|
449
|
-
dbfile = abcs[
|
451
|
+
when /sqlite/
|
452
|
+
dbfile = abcs['test']['database'] || abcs['test']['dbfile']
|
450
453
|
File.delete(dbfile) if File.exist?(dbfile)
|
451
|
-
when
|
452
|
-
dropfkscript = "#{abcs[
|
453
|
-
`osql -E -S #{abcs[
|
454
|
-
`osql -E -S #{abcs[
|
454
|
+
when 'sqlserver'
|
455
|
+
dropfkscript = "#{abcs['test']['host']}.#{abcs['test']['database']}.DP1".gsub(/\\/,'-')
|
456
|
+
`osql -E -S #{abcs['test']['host']} -d #{abcs['test']['database']} -i db\\#{dropfkscript}`
|
457
|
+
`osql -E -S #{abcs['test']['host']} -d #{abcs['test']['database']} -i db\\#{Rails.env}_structure.sql`
|
455
458
|
when "oci", "oracle"
|
456
459
|
ActiveRecord::Base.establish_connection(:test)
|
457
460
|
ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
|
458
461
|
ActiveRecord::Base.connection.execute(ddl)
|
459
462
|
end
|
460
|
-
when
|
463
|
+
when 'firebird'
|
461
464
|
ActiveRecord::Base.establish_connection(:test)
|
462
465
|
ActiveRecord::Base.connection.recreate_database!
|
463
466
|
else
|
464
|
-
raise "Task not supported by '#{abcs[
|
467
|
+
raise "Task not supported by '#{abcs['test']['adapter']}'"
|
465
468
|
end
|
466
469
|
end
|
467
470
|
|
468
471
|
# desc 'Check for pending migrations and load the test schema'
|
469
472
|
task :prepare => 'db:abort_if_pending_migrations' do
|
470
473
|
if defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
|
471
|
-
|
474
|
+
db_namespace[{ :sql => 'test:clone_structure', :ruby => 'test:load' }[ActiveRecord::Base.schema_format]].invoke
|
472
475
|
end
|
473
476
|
end
|
474
477
|
end
|
@@ -476,11 +479,11 @@ namespace :db do
|
|
476
479
|
namespace :sessions do
|
477
480
|
# desc "Creates a sessions migration for use with ActiveRecord::SessionStore"
|
478
481
|
task :create => :environment do
|
479
|
-
raise
|
482
|
+
raise 'Task unavailable to this database (no migration support)' unless ActiveRecord::Base.connection.supports_migrations?
|
480
483
|
require 'rails/generators'
|
481
484
|
Rails::Generators.configure!
|
482
485
|
require 'rails/generators/rails/session_migration/session_migration_generator'
|
483
|
-
Rails::Generators::SessionMigrationGenerator.start [ ENV[
|
486
|
+
Rails::Generators::SessionMigrationGenerator.start [ ENV['MIGRATION'] || 'add_sessions_table' ]
|
484
487
|
end
|
485
488
|
|
486
489
|
# desc "Clear the sessions table"
|
@@ -490,20 +493,48 @@ namespace :db do
|
|
490
493
|
end
|
491
494
|
end
|
492
495
|
|
496
|
+
namespace :railties do
|
497
|
+
namespace :install do
|
498
|
+
# desc "Copies missing migrations from Railties (e.g. plugins, engines). You can specify Railties to use with FROM=railtie1,railtie2"
|
499
|
+
task :migrations => :'db:load_config' do
|
500
|
+
to_load = ENV['FROM'].blank? ? :all : ENV['FROM'].split(",").map {|n| n.strip }
|
501
|
+
railties = {}
|
502
|
+
Rails.application.railties.all do |railtie|
|
503
|
+
next unless to_load == :all || to_load.include?(railtie.railtie_name)
|
504
|
+
|
505
|
+
if railtie.respond_to?(:paths) && (path = railtie.paths['db/migrate'].first)
|
506
|
+
railties[railtie.railtie_name] = path
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
on_skip = Proc.new do |name, migration|
|
511
|
+
puts "NOTE: Migration #{migration.basename} from #{name} has been skipped. Migration with the same name already exists."
|
512
|
+
end
|
513
|
+
|
514
|
+
on_copy = Proc.new do |name, migration, old_path|
|
515
|
+
puts "Copied migration #{migration.basename} from #{name}"
|
516
|
+
end
|
517
|
+
|
518
|
+
ActiveRecord::Migration.copy( ActiveRecord::Migrator.migrations_paths.first, railties,
|
519
|
+
:on_skip => on_skip, :on_copy => on_copy)
|
520
|
+
end
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
493
524
|
task 'test:prepare' => 'db:test:prepare'
|
494
525
|
|
495
526
|
def drop_database(config)
|
496
527
|
case config['adapter']
|
497
|
-
when
|
528
|
+
when /mysql/
|
498
529
|
ActiveRecord::Base.establish_connection(config)
|
499
530
|
ActiveRecord::Base.connection.drop_database config['database']
|
500
|
-
when
|
531
|
+
when /sqlite/
|
501
532
|
require 'pathname'
|
502
533
|
path = Pathname.new(config['database'])
|
503
534
|
file = path.absolute? ? path.to_s : File.join(Rails.root, path)
|
504
535
|
|
505
536
|
FileUtils.rm(file)
|
506
|
-
when
|
537
|
+
when /postgresql/
|
507
538
|
ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
|
508
539
|
ActiveRecord::Base.connection.drop_database config['database']
|
509
540
|
end
|
@@ -514,8 +545,8 @@ def session_table_name
|
|
514
545
|
end
|
515
546
|
|
516
547
|
def set_firebird_env(config)
|
517
|
-
ENV[
|
518
|
-
ENV[
|
548
|
+
ENV['ISC_USER'] = config['username'].to_s if config['username']
|
549
|
+
ENV['ISC_PASSWORD'] = config['password'].to_s if config['password']
|
519
550
|
end
|
520
551
|
|
521
552
|
def firebird_db_string(config)
|