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