activerecord 3.1.12 → 3.2.0.rc1
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.md +6263 -103
- data/README.rdoc +2 -2
- data/examples/performance.rb +55 -31
- data/lib/active_record.rb +28 -2
- data/lib/active_record/aggregations.rb +2 -2
- data/lib/active_record/associations.rb +82 -69
- data/lib/active_record/associations/association.rb +2 -37
- data/lib/active_record/associations/association_scope.rb +3 -30
- data/lib/active_record/associations/builder/association.rb +6 -4
- data/lib/active_record/associations/builder/belongs_to.rb +3 -3
- data/lib/active_record/associations/builder/collection_association.rb +2 -2
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +5 -6
- data/lib/active_record/associations/builder/singular_association.rb +3 -16
- data/lib/active_record/associations/collection_association.rb +55 -28
- data/lib/active_record/associations/collection_proxy.rb +1 -35
- data/lib/active_record/associations/has_many_association.rb +5 -1
- data/lib/active_record/associations/has_many_through_association.rb +11 -8
- data/lib/active_record/associations/join_dependency.rb +1 -1
- data/lib/active_record/associations/preloader/association.rb +3 -1
- data/lib/active_record/attribute_assignment.rb +221 -0
- data/lib/active_record/attribute_methods.rb +212 -32
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +32 -0
- data/lib/active_record/attribute_methods/dirty.rb +3 -3
- data/lib/active_record/attribute_methods/primary_key.rb +62 -25
- data/lib/active_record/attribute_methods/read.rb +69 -80
- data/lib/active_record/attribute_methods/serialization.rb +89 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +9 -14
- data/lib/active_record/attribute_methods/write.rb +27 -5
- data/lib/active_record/autosave_association.rb +23 -8
- data/lib/active_record/base.rb +223 -1712
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +98 -132
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +82 -29
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +13 -42
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +7 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +36 -25
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +41 -13
- data/lib/active_record/connection_adapters/abstract_adapter.rb +78 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +653 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +138 -578
- data/lib/active_record/connection_adapters/mysql_adapter.rb +86 -658
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +144 -94
- data/lib/active_record/connection_adapters/schema_cache.rb +50 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -6
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +43 -22
- data/lib/active_record/counter_cache.rb +1 -1
- data/lib/active_record/dynamic_matchers.rb +79 -0
- data/lib/active_record/errors.rb +11 -1
- data/lib/active_record/explain.rb +83 -0
- data/lib/active_record/explain_subscriber.rb +21 -0
- data/lib/active_record/fixtures.rb +31 -76
- data/lib/active_record/fixtures/file.rb +65 -0
- data/lib/active_record/identity_map.rb +1 -7
- data/lib/active_record/inheritance.rb +167 -0
- data/lib/active_record/integration.rb +49 -0
- data/lib/active_record/locking/optimistic.rb +19 -11
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +3 -3
- data/lib/active_record/migration.rb +38 -29
- data/lib/active_record/migration/command_recorder.rb +7 -7
- data/lib/active_record/model_schema.rb +362 -0
- data/lib/active_record/nested_attributes.rb +3 -2
- data/lib/active_record/persistence.rb +51 -1
- data/lib/active_record/querying.rb +58 -0
- data/lib/active_record/railtie.rb +24 -28
- data/lib/active_record/railties/controller_runtime.rb +3 -1
- data/lib/active_record/railties/databases.rake +133 -77
- data/lib/active_record/readonly_attributes.rb +26 -0
- data/lib/active_record/reflection.rb +7 -15
- data/lib/active_record/relation.rb +78 -35
- data/lib/active_record/relation/batches.rb +5 -2
- data/lib/active_record/relation/calculations.rb +27 -6
- data/lib/active_record/relation/delegation.rb +49 -0
- data/lib/active_record/relation/finder_methods.rb +5 -4
- data/lib/active_record/relation/predicate_builder.rb +13 -16
- data/lib/active_record/relation/query_methods.rb +59 -4
- data/lib/active_record/result.rb +1 -1
- data/lib/active_record/sanitization.rb +194 -0
- data/lib/active_record/schema_dumper.rb +5 -2
- data/lib/active_record/scoping.rb +152 -0
- data/lib/active_record/scoping/default.rb +140 -0
- data/lib/active_record/scoping/named.rb +202 -0
- data/lib/active_record/serialization.rb +1 -43
- data/lib/active_record/serializers/xml_serializer.rb +2 -44
- data/lib/active_record/session_store.rb +11 -11
- data/lib/active_record/store.rb +50 -0
- data/lib/active_record/test_case.rb +11 -7
- data/lib/active_record/timestamp.rb +16 -3
- data/lib/active_record/transactions.rb +5 -5
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/validations.rb +1 -1
- data/lib/active_record/validations/associated.rb +5 -4
- data/lib/active_record/validations/uniqueness.rb +4 -4
- data/lib/active_record/version.rb +3 -3
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +1 -5
- metadata +48 -38
- checksums.yaml +0 -7
- data/lib/active_record/named_scope.rb +0 -200
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Querying
|
5
|
+
delegate :find, :first, :first!, :last, :last!, :all, :exists?, :any?, :many?, :to => :scoped
|
6
|
+
delegate :first_or_create, :first_or_create!, :first_or_initialize, :to => :scoped
|
7
|
+
delegate :destroy, :destroy_all, :delete, :delete_all, :update, :update_all, :to => :scoped
|
8
|
+
delegate :find_each, :find_in_batches, :to => :scoped
|
9
|
+
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
|
10
|
+
:where, :preload, :eager_load, :includes, :from, :lock, :readonly,
|
11
|
+
:having, :create_with, :uniq, :to => :scoped
|
12
|
+
delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :to => :scoped
|
13
|
+
|
14
|
+
# Executes a custom SQL query against your database and returns all the results. The results will
|
15
|
+
# be returned as an array with columns requested encapsulated as attributes of the model you call
|
16
|
+
# this method from. If you call <tt>Product.find_by_sql</tt> then the results will be returned in
|
17
|
+
# a Product object with the attributes you specified in the SQL query.
|
18
|
+
#
|
19
|
+
# If you call a complicated SQL query which spans multiple tables the columns specified by the
|
20
|
+
# SELECT will be attributes of the model, whether or not they are columns of the corresponding
|
21
|
+
# table.
|
22
|
+
#
|
23
|
+
# The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be
|
24
|
+
# no database agnostic conversions performed. This should be a last resort because using, for example,
|
25
|
+
# MySQL specific terms will lock you to using that particular database engine or require you to
|
26
|
+
# change your call if you switch engines.
|
27
|
+
#
|
28
|
+
# ==== Examples
|
29
|
+
# # A simple SQL query spanning multiple tables
|
30
|
+
# Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
|
31
|
+
# > [#<Post:0x36bff9c @attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
|
32
|
+
#
|
33
|
+
# # You can use the same string replacement techniques as you can with ActiveRecord#find
|
34
|
+
# Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
|
35
|
+
# > [#<Post:0x36bff9c @attributes={"title"=>"The Cheap Man Buys Twice"}>, ...]
|
36
|
+
def find_by_sql(sql, binds = [])
|
37
|
+
logging_query_plan do
|
38
|
+
connection.select_all(sanitize_sql(sql), "#{name} Load", binds).collect! { |record| instantiate(record) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
|
43
|
+
# The use of this method should be restricted to complicated SQL queries that can't be executed
|
44
|
+
# using the ActiveRecord::Calculations class methods. Look into those before using this.
|
45
|
+
#
|
46
|
+
# ==== Parameters
|
47
|
+
#
|
48
|
+
# * +sql+ - An SQL statement which should return a count query from the database, see the example below.
|
49
|
+
#
|
50
|
+
# ==== Examples
|
51
|
+
#
|
52
|
+
# Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
|
53
|
+
def count_by_sql(sql)
|
54
|
+
sql = sanitize_conditions(sql)
|
55
|
+
connection.select_value(sql, "#{name} Count").to_i
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -22,6 +22,13 @@ module ActiveRecord
|
|
22
22
|
config.app_middleware.insert_after "::ActionDispatch::Callbacks",
|
23
23
|
"ActiveRecord::ConnectionAdapters::ConnectionManagement"
|
24
24
|
|
25
|
+
config.action_dispatch.rescue_responses.merge!(
|
26
|
+
'ActiveRecord::RecordNotFound' => :not_found,
|
27
|
+
'ActiveRecord::StaleObjectError' => :conflict,
|
28
|
+
'ActiveRecord::RecordInvalid' => :unprocessable_entity,
|
29
|
+
'ActiveRecord::RecordNotSaved' => :unprocessable_entity
|
30
|
+
)
|
31
|
+
|
25
32
|
rake_tasks do
|
26
33
|
load "active_record/railties/databases.rake"
|
27
34
|
end
|
@@ -78,15 +85,27 @@ module ActiveRecord
|
|
78
85
|
end
|
79
86
|
end
|
80
87
|
|
81
|
-
initializer "active_record.
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
88
|
+
initializer "active_record.set_reloader_hooks" do |app|
|
89
|
+
hook = lambda do
|
90
|
+
ActiveRecord::Base.clear_reloadable_connections!
|
91
|
+
ActiveRecord::Base.clear_cache!
|
92
|
+
end
|
93
|
+
|
94
|
+
if app.config.reload_classes_only_on_change
|
95
|
+
ActiveSupport.on_load(:active_record) do
|
96
|
+
ActionDispatch::Reloader.to_prepare(&hook)
|
97
|
+
end
|
98
|
+
else
|
99
|
+
ActiveSupport.on_load(:active_record) do
|
100
|
+
ActionDispatch::Reloader.to_cleanup(&hook)
|
86
101
|
end
|
87
102
|
end
|
88
103
|
end
|
89
104
|
|
105
|
+
initializer "active_record.add_watchable_files" do |app|
|
106
|
+
config.watchable_files.concat ["#{app.root}/db/schema.rb", "#{app.root}/db/structure.sql"]
|
107
|
+
end
|
108
|
+
|
90
109
|
config.after_initialize do
|
91
110
|
ActiveSupport.on_load(:active_record) do
|
92
111
|
instantiate_observers
|
@@ -96,28 +115,5 @@ module ActiveRecord
|
|
96
115
|
end
|
97
116
|
end
|
98
117
|
end
|
99
|
-
|
100
|
-
config.after_initialize do
|
101
|
-
container = :"activerecord.attributes"
|
102
|
-
lookup = I18n.t(container, :default => {})
|
103
|
-
if lookup.is_a?(Hash)
|
104
|
-
lookup.each do |key, value|
|
105
|
-
if value.is_a?(Hash) && value.any? { |k,v| v.is_a?(Hash) }
|
106
|
-
$stderr.puts "[DEPRECATION WARNING] Nested I18n namespace lookup under \"#{container}.#{key}\" is no longer supported"
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
container = :"activerecord.models"
|
112
|
-
lookup = I18n.t(container, :default => {})
|
113
|
-
if lookup.is_a?(Hash)
|
114
|
-
lookup.each do |key, value|
|
115
|
-
if value.is_a?(Hash) && !value.key?(:one)
|
116
|
-
$stderr.puts "[DEPRECATION WARNING] Nested I18n namespace lookup under \"#{container}.#{key}\" is no longer supported"
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
118
|
end
|
123
119
|
end
|
@@ -32,7 +32,9 @@ module ActiveRecord
|
|
32
32
|
|
33
33
|
def append_info_to_payload(payload)
|
34
34
|
super
|
35
|
-
|
35
|
+
if ActiveRecord::Base.connected?
|
36
|
+
payload[:db_runtime] = (db_runtime || 0) + ActiveRecord::LogSubscriber.reset_runtime
|
37
|
+
end
|
36
38
|
end
|
37
39
|
|
38
40
|
module ClassMethods
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'active_support/core_ext/object/inclusion'
|
2
|
+
require 'active_record'
|
2
3
|
|
3
4
|
db_namespace = namespace :db do
|
4
5
|
task :load_config => :rails_env do
|
5
|
-
require 'active_record'
|
6
6
|
ActiveRecord::Base.configurations = Rails.application.config.database_configuration
|
7
7
|
ActiveRecord::Migrator.migrations_paths = Rails.application.paths['db/migrate'].to_a
|
8
8
|
|
@@ -27,7 +27,7 @@ db_namespace = namespace :db do
|
|
27
27
|
#
|
28
28
|
# development:
|
29
29
|
# database: blog_development
|
30
|
-
#
|
30
|
+
# *defaults
|
31
31
|
next unless config['database']
|
32
32
|
# Only connect to local databases
|
33
33
|
local_database?(config) { create_database(config) }
|
@@ -37,11 +37,7 @@ db_namespace = namespace :db do
|
|
37
37
|
|
38
38
|
desc 'Create the database from config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)'
|
39
39
|
task :create => :load_config do
|
40
|
-
|
41
|
-
if Rails.env.development? && ActiveRecord::Base.configurations['test']
|
42
|
-
create_database(ActiveRecord::Base.configurations['test'])
|
43
|
-
end
|
44
|
-
create_database(ActiveRecord::Base.configurations[Rails.env])
|
40
|
+
configs_for_environment.each { |config| create_database(config) }
|
45
41
|
end
|
46
42
|
|
47
43
|
def mysql_creation_options(config)
|
@@ -138,12 +134,7 @@ db_namespace = namespace :db do
|
|
138
134
|
|
139
135
|
desc 'Drops the database for the current Rails.env (use db:drop:all to drop all databases)'
|
140
136
|
task :drop => :load_config do
|
141
|
-
|
142
|
-
begin
|
143
|
-
drop_database(config)
|
144
|
-
rescue Exception => e
|
145
|
-
$stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
|
146
|
-
end
|
137
|
+
configs_for_environment.each { |config| drop_database_and_rescue(config) }
|
147
138
|
end
|
148
139
|
|
149
140
|
def local_database?(config, &block)
|
@@ -158,8 +149,19 @@ db_namespace = namespace :db do
|
|
158
149
|
desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
|
159
150
|
task :migrate => [:environment, :load_config] do
|
160
151
|
ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
|
161
|
-
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
|
162
|
-
|
152
|
+
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration|
|
153
|
+
ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
|
154
|
+
end
|
155
|
+
db_namespace['_dump'].invoke
|
156
|
+
end
|
157
|
+
|
158
|
+
task :_dump do
|
159
|
+
case ActiveRecord::Base.schema_format
|
160
|
+
when :ruby then db_namespace["schema:dump"].invoke
|
161
|
+
when :sql then db_namespace["structure:dump"].invoke
|
162
|
+
else
|
163
|
+
raise "unknown schema format #{ActiveRecord::Base.schema_format}"
|
164
|
+
end
|
163
165
|
end
|
164
166
|
|
165
167
|
namespace :migrate do
|
@@ -182,7 +184,7 @@ db_namespace = namespace :db do
|
|
182
184
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
183
185
|
raise 'VERSION is required' unless version
|
184
186
|
ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
|
185
|
-
db_namespace['
|
187
|
+
db_namespace['_dump'].invoke
|
186
188
|
end
|
187
189
|
|
188
190
|
# desc 'Runs the "down" for a given migration VERSION.'
|
@@ -190,7 +192,7 @@ db_namespace = namespace :db do
|
|
190
192
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
191
193
|
raise 'VERSION is required' unless version
|
192
194
|
ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
|
193
|
-
db_namespace['
|
195
|
+
db_namespace['_dump'].invoke
|
194
196
|
end
|
195
197
|
|
196
198
|
desc 'Display status of migrations'
|
@@ -230,18 +232,21 @@ db_namespace = namespace :db do
|
|
230
232
|
task :rollback => [:environment, :load_config] do
|
231
233
|
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
232
234
|
ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
|
233
|
-
db_namespace['
|
235
|
+
db_namespace['_dump'].invoke
|
234
236
|
end
|
235
237
|
|
236
238
|
# desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
|
237
239
|
task :forward => [:environment, :load_config] do
|
238
240
|
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
239
241
|
ActiveRecord::Migrator.forward(ActiveRecord::Migrator.migrations_paths, step)
|
240
|
-
db_namespace['
|
242
|
+
db_namespace['_dump'].invoke
|
241
243
|
end
|
242
244
|
|
243
245
|
# desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
|
244
|
-
task :reset =>
|
246
|
+
task :reset => :environment do
|
247
|
+
db_namespace["drop"].invoke
|
248
|
+
db_namespace["setup"].invoke
|
249
|
+
end
|
245
250
|
|
246
251
|
# desc "Retrieves the charset for the current environment's database"
|
247
252
|
task :charset => :environment do
|
@@ -280,29 +285,28 @@ db_namespace = namespace :db do
|
|
280
285
|
|
281
286
|
# desc "Raises an error if there are pending migrations"
|
282
287
|
task :abort_if_pending_migrations => :environment do
|
283
|
-
|
284
|
-
pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_paths).pending_migrations
|
288
|
+
pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_paths).pending_migrations
|
285
289
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
end
|
291
|
-
abort %{Run "rake db:migrate" to update your database then try again.}
|
290
|
+
if pending_migrations.any?
|
291
|
+
puts "You have #{pending_migrations.size} pending migrations:"
|
292
|
+
pending_migrations.each do |pending_migration|
|
293
|
+
puts ' %4d %s' % [pending_migration.version, pending_migration.name]
|
292
294
|
end
|
295
|
+
abort %{Run `rake db:migrate` to update your database then try again.}
|
293
296
|
end
|
294
297
|
end
|
295
298
|
|
296
299
|
desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)'
|
297
|
-
task :setup => [
|
300
|
+
task :setup => ['db:schema:load_if_ruby', 'db:structure:load_if_sql', :seed]
|
298
301
|
|
299
302
|
desc 'Load the seed data from db/seeds.rb'
|
300
|
-
task :seed
|
303
|
+
task :seed do
|
304
|
+
db_namespace['abort_if_pending_migrations'].invoke
|
301
305
|
Rails.application.load_seed
|
302
306
|
end
|
303
307
|
|
304
308
|
namespace :fixtures do
|
305
|
-
desc "Load fixtures into the current environment's database.
|
309
|
+
desc "Load fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
|
306
310
|
task :load => :environment do
|
307
311
|
require 'active_record/fixtures'
|
308
312
|
|
@@ -357,93 +361,125 @@ db_namespace = namespace :db do
|
|
357
361
|
if File.exists?(file)
|
358
362
|
load(file)
|
359
363
|
else
|
360
|
-
abort %{#{file} doesn't exist yet. Run
|
364
|
+
abort %{#{file} doesn't exist yet. Run `rake db:migrate` to create it then try again. If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded}
|
361
365
|
end
|
362
366
|
end
|
367
|
+
|
368
|
+
task :load_if_ruby => 'db:create' do
|
369
|
+
db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :ruby
|
370
|
+
end
|
363
371
|
end
|
364
372
|
|
365
373
|
namespace :structure do
|
366
|
-
desc 'Dump the database structure to
|
374
|
+
desc 'Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql'
|
367
375
|
task :dump => :environment do
|
368
376
|
abcs = ActiveRecord::Base.configurations
|
377
|
+
filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
|
369
378
|
case abcs[Rails.env]['adapter']
|
370
379
|
when /mysql/, 'oci', 'oracle'
|
371
380
|
ActiveRecord::Base.establish_connection(abcs[Rails.env])
|
372
|
-
File.open(
|
381
|
+
File.open(filename, "w:utf-8") { |f| f << ActiveRecord::Base.connection.structure_dump }
|
373
382
|
when /postgresql/
|
374
|
-
|
375
|
-
ENV['PGPORT'] = abcs[Rails.env]["port"].to_s if abcs[Rails.env]['port']
|
376
|
-
ENV['PGPASSWORD'] = abcs[Rails.env]['password'].to_s if abcs[Rails.env]['password']
|
383
|
+
set_psql_env(abcs[Rails.env])
|
377
384
|
search_path = abcs[Rails.env]['schema_search_path']
|
378
385
|
unless search_path.blank?
|
379
|
-
search_path = search_path.split(",").map{|
|
386
|
+
search_path = search_path.split(",").map{|search_path_part| "--schema=#{search_path_part.strip}" }.join(" ")
|
380
387
|
end
|
381
|
-
`pg_dump -i -
|
388
|
+
`pg_dump -i -s -x -O -f #{filename} #{search_path} #{abcs[Rails.env]['database']}`
|
382
389
|
raise 'Error dumping database' if $?.exitstatus == 1
|
383
390
|
when /sqlite/
|
384
|
-
dbfile = abcs[Rails.env]['database']
|
385
|
-
`sqlite3 #{dbfile} .schema >
|
391
|
+
dbfile = abcs[Rails.env]['database']
|
392
|
+
`sqlite3 #{dbfile} .schema > #{filename}`
|
386
393
|
when 'sqlserver'
|
387
|
-
`smoscript -s #{abcs[Rails.env]['host']} -d #{abcs[Rails.env]['database']} -u #{abcs[Rails.env]['username']} -p #{abcs[Rails.env]['password']} -f
|
394
|
+
`smoscript -s #{abcs[Rails.env]['host']} -d #{abcs[Rails.env]['database']} -u #{abcs[Rails.env]['username']} -p #{abcs[Rails.env]['password']} -f #{filename} -A -U`
|
388
395
|
when "firebird"
|
389
396
|
set_firebird_env(abcs[Rails.env])
|
390
397
|
db_string = firebird_db_string(abcs[Rails.env])
|
391
|
-
sh "isql -a #{db_string} > #{
|
398
|
+
sh "isql -a #{db_string} > #{filename}"
|
392
399
|
else
|
393
400
|
raise "Task not supported by '#{abcs[Rails.env]["adapter"]}'"
|
394
401
|
end
|
395
402
|
|
396
403
|
if ActiveRecord::Base.connection.supports_migrations?
|
397
|
-
File.open(
|
404
|
+
File.open(filename, "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
|
398
405
|
end
|
399
406
|
end
|
400
|
-
end
|
401
|
-
|
402
|
-
namespace :test do
|
403
|
-
# desc "Recreate the test database from the current schema.rb"
|
404
|
-
task :load => 'db:test:purge' do
|
405
|
-
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
|
406
|
-
ActiveRecord::Schema.verbose = false
|
407
|
-
db_namespace['schema:load'].invoke
|
408
|
-
end
|
409
407
|
|
410
|
-
# desc "Recreate the
|
411
|
-
task :
|
408
|
+
# desc "Recreate the databases from the structure.sql file"
|
409
|
+
task :load => [:environment, :load_config] do
|
410
|
+
env = ENV['RAILS_ENV'] || 'test'
|
412
411
|
|
413
|
-
# desc "Recreate the test databases from the development structure"
|
414
|
-
task :clone_structure => [ 'db:structure:dump', 'db:test:purge' ] do
|
415
412
|
abcs = ActiveRecord::Base.configurations
|
416
|
-
|
413
|
+
filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
|
414
|
+
case abcs[env]['adapter']
|
417
415
|
when /mysql/
|
418
|
-
ActiveRecord::Base.establish_connection(
|
416
|
+
ActiveRecord::Base.establish_connection(abcs[env])
|
419
417
|
ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
|
420
|
-
IO.
|
418
|
+
IO.read(filename).split("\n\n").each do |table|
|
421
419
|
ActiveRecord::Base.connection.execute(table)
|
422
420
|
end
|
423
421
|
when /postgresql/
|
424
|
-
|
425
|
-
|
426
|
-
ENV['PGPASSWORD'] = abcs['test']['password'].to_s if abcs['test']['password']
|
427
|
-
`psql -U "#{abcs['test']['username']}" -f "#{Rails.root}/db/#{Rails.env}_structure.sql" #{abcs['test']['database']} #{abcs['test']['template']}`
|
422
|
+
set_psql_env(abcs[env])
|
423
|
+
`psql -f "#{filename}" #{abcs[env]['database']} #{abcs[env]['template']}`
|
428
424
|
when /sqlite/
|
429
|
-
dbfile = abcs[
|
430
|
-
`sqlite3 #{dbfile} < "#{
|
425
|
+
dbfile = abcs[env]['database']
|
426
|
+
`sqlite3 #{dbfile} < "#{filename}"`
|
431
427
|
when 'sqlserver'
|
432
|
-
`sqlcmd -S #{abcs[
|
428
|
+
`sqlcmd -S #{abcs[env]['host']} -d #{abcs[env]['database']} -U #{abcs[env]['username']} -P #{abcs[env]['password']} -i #{filename}`
|
433
429
|
when 'oci', 'oracle'
|
434
|
-
ActiveRecord::Base.establish_connection(
|
435
|
-
IO.
|
430
|
+
ActiveRecord::Base.establish_connection(abcs[env])
|
431
|
+
IO.read(filename).split(";\n\n").each do |ddl|
|
436
432
|
ActiveRecord::Base.connection.execute(ddl)
|
437
433
|
end
|
438
434
|
when 'firebird'
|
439
|
-
set_firebird_env(abcs[
|
440
|
-
db_string = firebird_db_string(abcs[
|
441
|
-
sh "isql -i #{
|
435
|
+
set_firebird_env(abcs[env])
|
436
|
+
db_string = firebird_db_string(abcs[env])
|
437
|
+
sh "isql -i #{filename} #{db_string}"
|
442
438
|
else
|
443
|
-
raise "Task not supported by '#{abcs[
|
439
|
+
raise "Task not supported by '#{abcs[env]['adapter']}'"
|
444
440
|
end
|
445
441
|
end
|
446
442
|
|
443
|
+
task :load_if_sql => 'db:create' do
|
444
|
+
db_namespace["structure:load"].invoke if ActiveRecord::Base.schema_format == :sql
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
namespace :test do
|
449
|
+
|
450
|
+
# desc "Recreate the test database from the current schema"
|
451
|
+
task :load => 'db:test:purge' do
|
452
|
+
case ActiveRecord::Base.schema_format
|
453
|
+
when :ruby
|
454
|
+
db_namespace["test:load_schema"].invoke
|
455
|
+
when :sql
|
456
|
+
db_namespace["test:load_structure"].invoke
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
# desc "Recreate the test database from an existent structure.sql file"
|
461
|
+
task :load_structure => 'db:test:purge' do
|
462
|
+
begin
|
463
|
+
old_env, ENV['RAILS_ENV'] = ENV['RAILS_ENV'], 'test'
|
464
|
+
db_namespace["structure:load"].invoke
|
465
|
+
ensure
|
466
|
+
ENV['RAILS_ENV'] = old_env
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
# desc "Recreate the test database from an existent schema.rb file"
|
471
|
+
task :load_schema => 'db:test:purge' do
|
472
|
+
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
|
473
|
+
ActiveRecord::Schema.verbose = false
|
474
|
+
db_namespace["schema:load"].invoke
|
475
|
+
end
|
476
|
+
|
477
|
+
# desc "Recreate the test database from a fresh schema.rb file"
|
478
|
+
task :clone => %w(db:schema:dump db:test:load_schema)
|
479
|
+
|
480
|
+
# desc "Recreate the test database from a fresh structure.sql file"
|
481
|
+
task :clone_structure => [ "db:structure:dump", "db:test:load_structure" ]
|
482
|
+
|
447
483
|
# desc "Empty the test database"
|
448
484
|
task :purge => :environment do
|
449
485
|
abcs = ActiveRecord::Base.configurations
|
@@ -456,7 +492,7 @@ db_namespace = namespace :db do
|
|
456
492
|
drop_database(abcs['test'])
|
457
493
|
create_database(abcs['test'])
|
458
494
|
when /sqlite/
|
459
|
-
dbfile = abcs['test']['database']
|
495
|
+
dbfile = abcs['test']['database']
|
460
496
|
File.delete(dbfile) if File.exist?(dbfile)
|
461
497
|
when 'sqlserver'
|
462
498
|
test = abcs.deep_dup['test']
|
@@ -479,7 +515,7 @@ db_namespace = namespace :db do
|
|
479
515
|
|
480
516
|
# desc 'Check for pending migrations and load the test schema'
|
481
517
|
task :prepare => 'db:abort_if_pending_migrations' do
|
482
|
-
|
518
|
+
unless ActiveRecord::Base.configurations.blank?
|
483
519
|
db_namespace[{ :sql => 'test:clone_structure', :ruby => 'test:load' }[ActiveRecord::Base.schema_format]].invoke
|
484
520
|
end
|
485
521
|
end
|
@@ -489,8 +525,7 @@ db_namespace = namespace :db do
|
|
489
525
|
# desc "Creates a sessions migration for use with ActiveRecord::SessionStore"
|
490
526
|
task :create => :environment do
|
491
527
|
raise 'Task unavailable to this database (no migration support)' unless ActiveRecord::Base.connection.supports_migrations?
|
492
|
-
|
493
|
-
Rails::Generators.configure!
|
528
|
+
Rails.application.load_generators
|
494
529
|
require 'rails/generators/rails/session_migration/session_migration_generator'
|
495
530
|
Rails::Generators::SessionMigrationGenerator.start [ ENV['MIGRATION'] || 'add_sessions_table' ]
|
496
531
|
end
|
@@ -549,6 +584,20 @@ def drop_database(config)
|
|
549
584
|
end
|
550
585
|
end
|
551
586
|
|
587
|
+
def drop_database_and_rescue(config)
|
588
|
+
begin
|
589
|
+
drop_database(config)
|
590
|
+
rescue Exception => e
|
591
|
+
$stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
def configs_for_environment
|
596
|
+
environments = [Rails.env]
|
597
|
+
environments << 'test' if Rails.env.development?
|
598
|
+
ActiveRecord::Base.configurations.values_at(*environments).compact.reject { |config| config['database'].blank? }
|
599
|
+
end
|
600
|
+
|
552
601
|
def session_table_name
|
553
602
|
ActiveRecord::SessionStore::Session.table_name
|
554
603
|
end
|
@@ -561,3 +610,10 @@ end
|
|
561
610
|
def firebird_db_string(config)
|
562
611
|
FireRuby::Database.db_string_for(config.symbolize_keys)
|
563
612
|
end
|
613
|
+
|
614
|
+
def set_psql_env(config)
|
615
|
+
ENV['PGHOST'] = config['host'] if config['host']
|
616
|
+
ENV['PGPORT'] = config['port'].to_s if config['port']
|
617
|
+
ENV['PGPASSWORD'] = config['password'].to_s if config['password']
|
618
|
+
ENV['PGUSER'] = config['username'].to_s if config['username']
|
619
|
+
end
|