activerecord 3.1.9 → 3.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +6 -6
- data/CHANGELOG.md +317 -336
- 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 +3 -42
- data/lib/active_record/associations/association_scope.rb +3 -15
- 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 +64 -31
- data/lib/active_record/associations/collection_proxy.rb +2 -37
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +1 -0
- data/lib/active_record/associations/has_many_association.rb +5 -1
- data/lib/active_record/associations/has_many_through_association.rb +28 -9
- data/lib/active_record/associations/has_one_association.rb +15 -13
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/preloader.rb +14 -10
- data/lib/active_record/associations/through_association.rb +7 -3
- 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 +102 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +23 -17
- data/lib/active_record/attribute_methods/write.rb +31 -6
- data/lib/active_record/attribute_methods.rb +231 -30
- data/lib/active_record/autosave_association.rb +43 -22
- 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 +6 -33
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +10 -2
- data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +37 -26
- 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 +674 -0
- data/lib/active_record/connection_adapters/column.rb +37 -11
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +129 -581
- data/lib/active_record/connection_adapters/mysql_adapter.rb +137 -696
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -86
- 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 +55 -32
- 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 +85 -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 +56 -85
- data/lib/active_record/identity_map.rb +3 -4
- data/lib/active_record/inheritance.rb +174 -0
- data/lib/active_record/integration.rb +49 -0
- data/lib/active_record/locking/optimistic.rb +30 -25
- data/lib/active_record/locking/pessimistic.rb +23 -1
- data/lib/active_record/log_subscriber.rb +3 -3
- 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 +366 -0
- data/lib/active_record/nested_attributes.rb +3 -2
- data/lib/active_record/persistence.rb +57 -11
- data/lib/active_record/querying.rb +58 -0
- data/lib/active_record/railtie.rb +31 -29
- data/lib/active_record/railties/controller_runtime.rb +3 -1
- data/lib/active_record/railties/databases.rake +191 -110
- 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 +5 -2
- data/lib/active_record/relation/calculations.rb +47 -15
- data/lib/active_record/relation/delegation.rb +49 -0
- data/lib/active_record/relation/finder_methods.rb +9 -7
- data/lib/active_record/relation/predicate_builder.rb +18 -7
- data/lib/active_record/relation/query_methods.rb +75 -9
- data/lib/active_record/relation/spawn_methods.rb +11 -2
- data/lib/active_record/relation.rb +78 -32
- data/lib/active_record/result.rb +1 -1
- 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 +202 -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 +17 -15
- 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 +7 -7
- data/lib/active_record/validations.rb +1 -1
- data/lib/active_record/version.rb +2 -2
- 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 +30 -10
- 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,20 @@ 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
|
|
|
47
67
|
def mysql_creation_options(config)
|
|
48
68
|
@charset = ENV['CHARSET'] || 'utf8'
|
|
49
69
|
@collation = ENV['COLLATION'] || 'utf8_unicode_ci'
|
|
50
|
-
{:charset => (config['
|
|
70
|
+
{:charset => (config['encoding'] || @charset), :collation => (config['collation'] || @collation)}
|
|
51
71
|
end
|
|
52
72
|
|
|
53
73
|
def create_database(config)
|
|
@@ -99,8 +119,8 @@ db_namespace = namespace :db do
|
|
|
99
119
|
ActiveRecord::Base.establish_connection(config)
|
|
100
120
|
else
|
|
101
121
|
$stderr.puts sqlerr.error
|
|
102
|
-
$stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['
|
|
103
|
-
$stderr.puts "(if you set the charset manually, make sure you have a matching collation)" if config['
|
|
122
|
+
$stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['encoding'] || @charset}, collation: #{config['collation'] || @collation}"
|
|
123
|
+
$stderr.puts "(if you set the charset manually, make sure you have a matching collation)" if config['encoding']
|
|
104
124
|
end
|
|
105
125
|
end
|
|
106
126
|
when /postgresql/
|
|
@@ -136,13 +156,12 @@ db_namespace = namespace :db do
|
|
|
136
156
|
end
|
|
137
157
|
end
|
|
138
158
|
|
|
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}"
|
|
159
|
+
desc 'Drops the database using DATABASE_URL or the current Rails.env (use db:drop:all to drop all databases)'
|
|
160
|
+
task :drop => [:load_config, :rails_env] do
|
|
161
|
+
if ENV['DATABASE_URL']
|
|
162
|
+
drop_database_and_rescue(database_url_config)
|
|
163
|
+
else
|
|
164
|
+
configs_for_environment.each { |config| drop_database_and_rescue(config) }
|
|
146
165
|
end
|
|
147
166
|
end
|
|
148
167
|
|
|
@@ -154,12 +173,25 @@ db_namespace = namespace :db do
|
|
|
154
173
|
end
|
|
155
174
|
end
|
|
156
175
|
|
|
157
|
-
|
|
158
176
|
desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
|
|
159
177
|
task :migrate => [:environment, :load_config] do
|
|
160
178
|
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
|
-
|
|
179
|
+
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) do |migration|
|
|
180
|
+
ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope)
|
|
181
|
+
end
|
|
182
|
+
db_namespace['_dump'].invoke
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
task :_dump do
|
|
186
|
+
case ActiveRecord::Base.schema_format
|
|
187
|
+
when :ruby then db_namespace["schema:dump"].invoke
|
|
188
|
+
when :sql then db_namespace["structure:dump"].invoke
|
|
189
|
+
else
|
|
190
|
+
raise "unknown schema format #{ActiveRecord::Base.schema_format}"
|
|
191
|
+
end
|
|
192
|
+
# Allow this task to be called as many times as required. An example is the
|
|
193
|
+
# migrate:redo task, which calls other two internally that depend on this one.
|
|
194
|
+
db_namespace['_dump'].reenable
|
|
163
195
|
end
|
|
164
196
|
|
|
165
197
|
namespace :migrate do
|
|
@@ -182,7 +214,7 @@ db_namespace = namespace :db do
|
|
|
182
214
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
|
183
215
|
raise 'VERSION is required' unless version
|
|
184
216
|
ActiveRecord::Migrator.run(:up, ActiveRecord::Migrator.migrations_paths, version)
|
|
185
|
-
db_namespace['
|
|
217
|
+
db_namespace['_dump'].invoke
|
|
186
218
|
end
|
|
187
219
|
|
|
188
220
|
# desc 'Runs the "down" for a given migration VERSION.'
|
|
@@ -190,13 +222,11 @@ db_namespace = namespace :db do
|
|
|
190
222
|
version = ENV['VERSION'] ? ENV['VERSION'].to_i : nil
|
|
191
223
|
raise 'VERSION is required' unless version
|
|
192
224
|
ActiveRecord::Migrator.run(:down, ActiveRecord::Migrator.migrations_paths, version)
|
|
193
|
-
db_namespace['
|
|
225
|
+
db_namespace['_dump'].invoke
|
|
194
226
|
end
|
|
195
227
|
|
|
196
228
|
desc 'Display status of migrations'
|
|
197
229
|
task :status => [:environment, :load_config] do
|
|
198
|
-
config = ActiveRecord::Base.configurations[Rails.env || 'development']
|
|
199
|
-
ActiveRecord::Base.establish_connection(config)
|
|
200
230
|
unless ActiveRecord::Base.connection.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name)
|
|
201
231
|
puts 'Schema migrations table does not exist yet.'
|
|
202
232
|
next # means "return" for rake task
|
|
@@ -216,7 +246,7 @@ db_namespace = namespace :db do
|
|
|
216
246
|
['up', version, '********** NO FILE **********']
|
|
217
247
|
end
|
|
218
248
|
# output
|
|
219
|
-
puts "\ndatabase: #{
|
|
249
|
+
puts "\ndatabase: #{ActiveRecord::Base.connection_config[:database]}\n\n"
|
|
220
250
|
puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
|
|
221
251
|
puts "-" * 50
|
|
222
252
|
(db_list + file_list).sort_by {|migration| migration[1]}.each do |migration|
|
|
@@ -230,22 +260,25 @@ db_namespace = namespace :db do
|
|
|
230
260
|
task :rollback => [:environment, :load_config] do
|
|
231
261
|
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
|
232
262
|
ActiveRecord::Migrator.rollback(ActiveRecord::Migrator.migrations_paths, step)
|
|
233
|
-
db_namespace['
|
|
263
|
+
db_namespace['_dump'].invoke
|
|
234
264
|
end
|
|
235
265
|
|
|
236
266
|
# desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
|
|
237
267
|
task :forward => [:environment, :load_config] do
|
|
238
268
|
step = ENV['STEP'] ? ENV['STEP'].to_i : 1
|
|
239
269
|
ActiveRecord::Migrator.forward(ActiveRecord::Migrator.migrations_paths, step)
|
|
240
|
-
db_namespace['
|
|
270
|
+
db_namespace['_dump'].invoke
|
|
241
271
|
end
|
|
242
272
|
|
|
243
273
|
# desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
|
|
244
|
-
task :reset => [
|
|
274
|
+
task :reset => [:environment, :load_config] do
|
|
275
|
+
db_namespace["drop"].invoke
|
|
276
|
+
db_namespace["setup"].invoke
|
|
277
|
+
end
|
|
245
278
|
|
|
246
279
|
# desc "Retrieves the charset for the current environment's database"
|
|
247
|
-
task :charset => :environment do
|
|
248
|
-
config = ActiveRecord::Base.configurations[Rails.env
|
|
280
|
+
task :charset => [:environment, :load_config] do
|
|
281
|
+
config = ActiveRecord::Base.configurations[Rails.env]
|
|
249
282
|
case config['adapter']
|
|
250
283
|
when /mysql/
|
|
251
284
|
ActiveRecord::Base.establish_connection(config)
|
|
@@ -262,8 +295,8 @@ db_namespace = namespace :db do
|
|
|
262
295
|
end
|
|
263
296
|
|
|
264
297
|
# desc "Retrieves the collation for the current environment's database"
|
|
265
|
-
task :collation => :environment do
|
|
266
|
-
config = ActiveRecord::Base.configurations[Rails.env
|
|
298
|
+
task :collation => [:environment, :load_config] do
|
|
299
|
+
config = ActiveRecord::Base.configurations[Rails.env]
|
|
267
300
|
case config['adapter']
|
|
268
301
|
when /mysql/
|
|
269
302
|
ActiveRecord::Base.establish_connection(config)
|
|
@@ -274,39 +307,37 @@ db_namespace = namespace :db do
|
|
|
274
307
|
end
|
|
275
308
|
|
|
276
309
|
desc 'Retrieves the current schema version number'
|
|
277
|
-
task :version => :environment do
|
|
310
|
+
task :version => [:environment, :load_config] do
|
|
278
311
|
puts "Current version: #{ActiveRecord::Migrator.current_version}"
|
|
279
312
|
end
|
|
280
313
|
|
|
281
314
|
# 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.}
|
|
315
|
+
task :abort_if_pending_migrations => [:environment, :load_config] do
|
|
316
|
+
pending_migrations = ActiveRecord::Migrator.new(:up, ActiveRecord::Migrator.migrations_paths).pending_migrations
|
|
317
|
+
|
|
318
|
+
if pending_migrations.any?
|
|
319
|
+
puts "You have #{pending_migrations.size} pending migrations:"
|
|
320
|
+
pending_migrations.each do |pending_migration|
|
|
321
|
+
puts ' %4d %s' % [pending_migration.version, pending_migration.name]
|
|
292
322
|
end
|
|
323
|
+
abort %{Run `rake db:migrate` to update your database then try again.}
|
|
293
324
|
end
|
|
294
325
|
end
|
|
295
326
|
|
|
296
327
|
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 => [
|
|
328
|
+
task :setup => ['db:schema:load_if_ruby', 'db:structure:load_if_sql', :seed]
|
|
298
329
|
|
|
299
330
|
desc 'Load the seed data from db/seeds.rb'
|
|
300
|
-
task :seed
|
|
331
|
+
task :seed do
|
|
332
|
+
db_namespace['abort_if_pending_migrations'].invoke
|
|
301
333
|
Rails.application.load_seed
|
|
302
334
|
end
|
|
303
335
|
|
|
304
336
|
namespace :fixtures do
|
|
305
|
-
desc "Load fixtures into the current environment's database.
|
|
306
|
-
task :load => :environment do
|
|
337
|
+
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."
|
|
338
|
+
task :load => [:environment, :load_config] do
|
|
307
339
|
require 'active_record/fixtures'
|
|
308
340
|
|
|
309
|
-
ActiveRecord::Base.establish_connection(Rails.env)
|
|
310
341
|
base_dir = File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
|
|
311
342
|
fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact
|
|
312
343
|
|
|
@@ -316,7 +347,7 @@ db_namespace = namespace :db do
|
|
|
316
347
|
end
|
|
317
348
|
|
|
318
349
|
# 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
|
|
350
|
+
task :identify => [:environment, :load_config] do
|
|
320
351
|
require 'active_record/fixtures'
|
|
321
352
|
|
|
322
353
|
label, id = ENV['LABEL'], ENV['ID']
|
|
@@ -345,107 +376,137 @@ db_namespace = namespace :db do
|
|
|
345
376
|
require 'active_record/schema_dumper'
|
|
346
377
|
filename = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
|
|
347
378
|
File.open(filename, "w:utf-8") do |file|
|
|
348
|
-
ActiveRecord::Base.establish_connection(Rails.env)
|
|
349
379
|
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
|
|
350
380
|
end
|
|
351
381
|
db_namespace['schema:dump'].reenable
|
|
352
382
|
end
|
|
353
383
|
|
|
354
384
|
desc 'Load a schema.rb file into the database'
|
|
355
|
-
task :load => :environment do
|
|
385
|
+
task :load => [:environment, :load_config] do
|
|
356
386
|
file = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
|
|
357
387
|
if File.exists?(file)
|
|
358
388
|
load(file)
|
|
359
389
|
else
|
|
360
|
-
abort %{#{file} doesn't exist yet. Run
|
|
390
|
+
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
391
|
end
|
|
362
392
|
end
|
|
393
|
+
|
|
394
|
+
task :load_if_ruby => ['db:create', :environment] do
|
|
395
|
+
db_namespace["schema:load"].invoke if ActiveRecord::Base.schema_format == :ruby
|
|
396
|
+
end
|
|
363
397
|
end
|
|
364
398
|
|
|
365
399
|
namespace :structure do
|
|
366
|
-
desc 'Dump the database structure to
|
|
367
|
-
task :dump => :environment do
|
|
368
|
-
|
|
369
|
-
|
|
400
|
+
desc 'Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql'
|
|
401
|
+
task :dump => [:environment, :load_config] do
|
|
402
|
+
config = current_config
|
|
403
|
+
filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
|
|
404
|
+
case config['adapter']
|
|
370
405
|
when /mysql/, 'oci', 'oracle'
|
|
371
|
-
ActiveRecord::Base.establish_connection(
|
|
372
|
-
File.open(
|
|
406
|
+
ActiveRecord::Base.establish_connection(config)
|
|
407
|
+
File.open(filename, "w:utf-8") { |f| f << ActiveRecord::Base.connection.structure_dump }
|
|
373
408
|
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']
|
|
409
|
+
set_psql_env(config)
|
|
410
|
+
search_path = config['schema_search_path']
|
|
378
411
|
unless search_path.blank?
|
|
379
|
-
search_path = search_path.split(",").map{|
|
|
412
|
+
search_path = search_path.split(",").map{|search_path_part| "--schema=#{Shellwords.escape(search_path_part.strip)}" }.join(" ")
|
|
380
413
|
end
|
|
381
|
-
`pg_dump -i -
|
|
414
|
+
`pg_dump -i -s -x -O -f #{Shellwords.escape(filename)} #{search_path} #{Shellwords.escape(config['database'])}`
|
|
382
415
|
raise 'Error dumping database' if $?.exitstatus == 1
|
|
383
416
|
when /sqlite/
|
|
384
|
-
dbfile =
|
|
385
|
-
`sqlite3 #{dbfile} .schema >
|
|
417
|
+
dbfile = config['database']
|
|
418
|
+
`sqlite3 #{dbfile} .schema > #{filename}`
|
|
386
419
|
when 'sqlserver'
|
|
387
|
-
`smoscript -s #{
|
|
420
|
+
`smoscript -s #{config['host']} -d #{config['database']} -u #{config['username']} -p #{config['password']} -f #{filename} -A -U`
|
|
388
421
|
when "firebird"
|
|
389
422
|
set_firebird_env(abcs[Rails.env])
|
|
390
423
|
db_string = firebird_db_string(abcs[Rails.env])
|
|
391
|
-
sh "isql -a #{db_string} > #{
|
|
424
|
+
sh "isql -a #{db_string} > #{filename}"
|
|
392
425
|
else
|
|
393
426
|
raise "Task not supported by '#{abcs[Rails.env]["adapter"]}'"
|
|
394
427
|
end
|
|
395
428
|
|
|
396
429
|
if ActiveRecord::Base.connection.supports_migrations?
|
|
397
|
-
File.open(
|
|
430
|
+
File.open(filename, "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
|
|
398
431
|
end
|
|
432
|
+
db_namespace['structure:dump'].reenable
|
|
399
433
|
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
|
-
|
|
410
|
-
# desc "Recreate the test database from the current environment's database schema"
|
|
411
|
-
task :clone => %w(db:schema:dump db:test:load)
|
|
412
434
|
|
|
413
|
-
# desc "Recreate the
|
|
414
|
-
task :
|
|
415
|
-
|
|
416
|
-
|
|
435
|
+
# desc "Recreate the databases from the structure.sql file"
|
|
436
|
+
task :load => [:environment, :load_config] do
|
|
437
|
+
config = current_config
|
|
438
|
+
filename = ENV['DB_STRUCTURE'] || File.join(Rails.root, "db", "structure.sql")
|
|
439
|
+
case config['adapter']
|
|
417
440
|
when /mysql/
|
|
418
|
-
ActiveRecord::Base.establish_connection(
|
|
441
|
+
ActiveRecord::Base.establish_connection(config)
|
|
419
442
|
ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
|
|
420
|
-
IO.
|
|
443
|
+
IO.read(filename).split("\n\n").each do |table|
|
|
421
444
|
ActiveRecord::Base.connection.execute(table)
|
|
422
445
|
end
|
|
423
446
|
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']}`
|
|
447
|
+
set_psql_env(config)
|
|
448
|
+
`psql -f "#{filename}" #{config['database']}`
|
|
428
449
|
when /sqlite/
|
|
429
|
-
dbfile =
|
|
430
|
-
`sqlite3 #{dbfile} < "#{
|
|
450
|
+
dbfile = config['database']
|
|
451
|
+
`sqlite3 #{dbfile} < "#{filename}"`
|
|
431
452
|
when 'sqlserver'
|
|
432
|
-
`sqlcmd -S #{
|
|
453
|
+
`sqlcmd -S #{config['host']} -d #{config['database']} -U #{config['username']} -P #{config['password']} -i #{filename}`
|
|
433
454
|
when 'oci', 'oracle'
|
|
434
|
-
ActiveRecord::Base.establish_connection(
|
|
435
|
-
IO.
|
|
455
|
+
ActiveRecord::Base.establish_connection(config)
|
|
456
|
+
IO.read(filename).split(";\n\n").each do |ddl|
|
|
436
457
|
ActiveRecord::Base.connection.execute(ddl)
|
|
437
458
|
end
|
|
438
459
|
when 'firebird'
|
|
439
|
-
set_firebird_env(
|
|
440
|
-
db_string = firebird_db_string(
|
|
441
|
-
sh "isql -i #{
|
|
460
|
+
set_firebird_env(config)
|
|
461
|
+
db_string = firebird_db_string(config)
|
|
462
|
+
sh "isql -i #{filename} #{db_string}"
|
|
442
463
|
else
|
|
443
|
-
raise "Task not supported by '#{
|
|
464
|
+
raise "Task not supported by '#{config['adapter']}'"
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
task :load_if_sql => ['db:create', :environment] do
|
|
469
|
+
db_namespace["structure:load"].invoke if ActiveRecord::Base.schema_format == :sql
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
namespace :test do
|
|
474
|
+
|
|
475
|
+
# desc "Recreate the test database from the current schema"
|
|
476
|
+
task :load => 'db:test:purge' do
|
|
477
|
+
case ActiveRecord::Base.schema_format
|
|
478
|
+
when :ruby
|
|
479
|
+
db_namespace["test:load_schema"].invoke
|
|
480
|
+
when :sql
|
|
481
|
+
db_namespace["test:load_structure"].invoke
|
|
444
482
|
end
|
|
445
483
|
end
|
|
446
484
|
|
|
485
|
+
# desc "Recreate the test database from an existent structure.sql file"
|
|
486
|
+
task :load_structure => 'db:test:purge' do
|
|
487
|
+
begin
|
|
488
|
+
current_config(:config => ActiveRecord::Base.configurations['test'])
|
|
489
|
+
db_namespace["structure:load"].invoke
|
|
490
|
+
ensure
|
|
491
|
+
current_config(:config => nil)
|
|
492
|
+
end
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
# desc "Recreate the test database from an existent schema.rb file"
|
|
496
|
+
task :load_schema => 'db:test:purge' do
|
|
497
|
+
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
|
|
498
|
+
ActiveRecord::Schema.verbose = false
|
|
499
|
+
db_namespace["schema:load"].invoke
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
# desc "Recreate the test database from a fresh schema.rb file"
|
|
503
|
+
task :clone => %w(db:schema:dump db:test:load_schema)
|
|
504
|
+
|
|
505
|
+
# desc "Recreate the test database from a fresh structure.sql file"
|
|
506
|
+
task :clone_structure => [ "db:structure:dump", "db:test:load_structure" ]
|
|
507
|
+
|
|
447
508
|
# desc "Empty the test database"
|
|
448
|
-
task :purge => :environment do
|
|
509
|
+
task :purge => [:environment, :load_config] do
|
|
449
510
|
abcs = ActiveRecord::Base.configurations
|
|
450
511
|
case abcs['test']['adapter']
|
|
451
512
|
when /mysql/
|
|
@@ -456,7 +517,7 @@ db_namespace = namespace :db do
|
|
|
456
517
|
drop_database(abcs['test'])
|
|
457
518
|
create_database(abcs['test'])
|
|
458
519
|
when /sqlite/
|
|
459
|
-
dbfile = abcs['test']['database']
|
|
520
|
+
dbfile = abcs['test']['database']
|
|
460
521
|
File.delete(dbfile) if File.exist?(dbfile)
|
|
461
522
|
when 'sqlserver'
|
|
462
523
|
test = abcs.deep_dup['test']
|
|
@@ -479,7 +540,7 @@ db_namespace = namespace :db do
|
|
|
479
540
|
|
|
480
541
|
# desc 'Check for pending migrations and load the test schema'
|
|
481
542
|
task :prepare => 'db:abort_if_pending_migrations' do
|
|
482
|
-
|
|
543
|
+
unless ActiveRecord::Base.configurations.blank?
|
|
483
544
|
db_namespace[{ :sql => 'test:clone_structure', :ruby => 'test:load' }[ActiveRecord::Base.schema_format]].invoke
|
|
484
545
|
end
|
|
485
546
|
end
|
|
@@ -487,16 +548,15 @@ db_namespace = namespace :db do
|
|
|
487
548
|
|
|
488
549
|
namespace :sessions do
|
|
489
550
|
# desc "Creates a sessions migration for use with ActiveRecord::SessionStore"
|
|
490
|
-
task :create => :environment do
|
|
551
|
+
task :create => [:environment, :load_config] do
|
|
491
552
|
raise 'Task unavailable to this database (no migration support)' unless ActiveRecord::Base.connection.supports_migrations?
|
|
492
|
-
|
|
493
|
-
Rails::Generators.configure!
|
|
553
|
+
Rails.application.load_generators
|
|
494
554
|
require 'rails/generators/rails/session_migration/session_migration_generator'
|
|
495
555
|
Rails::Generators::SessionMigrationGenerator.start [ ENV['MIGRATION'] || 'add_sessions_table' ]
|
|
496
556
|
end
|
|
497
557
|
|
|
498
558
|
# desc "Clear the sessions table"
|
|
499
|
-
task :clear => :environment do
|
|
559
|
+
task :clear => [:environment, :load_config] do
|
|
500
560
|
ActiveRecord::Base.connection.execute "DELETE FROM #{session_table_name}"
|
|
501
561
|
end
|
|
502
562
|
end
|
|
@@ -524,7 +584,7 @@ namespace :railties do
|
|
|
524
584
|
puts "Copied migration #{migration.basename} from #{name}"
|
|
525
585
|
end
|
|
526
586
|
|
|
527
|
-
ActiveRecord::Migration.copy(
|
|
587
|
+
ActiveRecord::Migration.copy(ActiveRecord::Migrator.migrations_paths.first, railties,
|
|
528
588
|
:on_skip => on_skip, :on_copy => on_copy)
|
|
529
589
|
end
|
|
530
590
|
end
|
|
@@ -549,6 +609,20 @@ def drop_database(config)
|
|
|
549
609
|
end
|
|
550
610
|
end
|
|
551
611
|
|
|
612
|
+
def drop_database_and_rescue(config)
|
|
613
|
+
begin
|
|
614
|
+
drop_database(config)
|
|
615
|
+
rescue Exception => e
|
|
616
|
+
$stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
|
|
617
|
+
end
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
def configs_for_environment
|
|
621
|
+
environments = [Rails.env]
|
|
622
|
+
environments << 'test' if Rails.env.development?
|
|
623
|
+
ActiveRecord::Base.configurations.values_at(*environments).compact.reject { |config| config['database'].blank? }
|
|
624
|
+
end
|
|
625
|
+
|
|
552
626
|
def session_table_name
|
|
553
627
|
ActiveRecord::SessionStore::Session.table_name
|
|
554
628
|
end
|
|
@@ -561,3 +635,10 @@ end
|
|
|
561
635
|
def firebird_db_string(config)
|
|
562
636
|
FireRuby::Database.db_string_for(config.symbolize_keys)
|
|
563
637
|
end
|
|
638
|
+
|
|
639
|
+
def set_psql_env(config)
|
|
640
|
+
ENV['PGHOST'] = config['host'] if config['host']
|
|
641
|
+
ENV['PGPORT'] = config['port'].to_s if config['port']
|
|
642
|
+
ENV['PGPASSWORD'] = config['password'].to_s if config['password']
|
|
643
|
+
ENV['PGUSER'] = config['username'].to_s if config['username']
|
|
644
|
+
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
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'active_support/core_ext/class/attribute'
|
|
2
|
-
require 'active_support/core_ext/module/deprecation'
|
|
3
2
|
require 'active_support/core_ext/object/inclusion'
|
|
4
3
|
|
|
5
4
|
module ActiveRecord
|
|
@@ -125,7 +124,7 @@ module ActiveRecord
|
|
|
125
124
|
# <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>'Money'</tt>
|
|
126
125
|
# <tt>has_many :clients</tt> returns <tt>'Client'</tt>
|
|
127
126
|
def class_name
|
|
128
|
-
@class_name ||= options[:class_name] || derive_class_name
|
|
127
|
+
@class_name ||= (options[:class_name] || derive_class_name).to_s
|
|
129
128
|
end
|
|
130
129
|
|
|
131
130
|
# Returns +true+ if +self+ and +other_aggregation+ have the same +name+ attribute, +active_record+ attribute,
|
|
@@ -178,15 +177,9 @@ module ActiveRecord
|
|
|
178
177
|
@collection = macro.in?([:has_many, :has_and_belongs_to_many])
|
|
179
178
|
end
|
|
180
179
|
|
|
181
|
-
# This is a hack so that we can tell if build_association was overridden, in order to
|
|
182
|
-
# provide an appropriate deprecation if the overridden method ignored the &block. Please
|
|
183
|
-
# see Association#build_record for details.
|
|
184
|
-
attr_accessor :original_build_association_called # :nodoc
|
|
185
|
-
|
|
186
180
|
# Returns a new, unsaved instance of the associated class. +options+ will
|
|
187
181
|
# be passed to the class's constructor.
|
|
188
182
|
def build_association(*options, &block)
|
|
189
|
-
@original_build_association_called = true
|
|
190
183
|
klass.new(*options, &block)
|
|
191
184
|
end
|
|
192
185
|
|
|
@@ -202,11 +195,6 @@ module ActiveRecord
|
|
|
202
195
|
@foreign_key ||= options[:foreign_key] || derive_foreign_key
|
|
203
196
|
end
|
|
204
197
|
|
|
205
|
-
def primary_key_name
|
|
206
|
-
foreign_key
|
|
207
|
-
end
|
|
208
|
-
deprecate :primary_key_name => :foreign_key
|
|
209
|
-
|
|
210
198
|
def foreign_type
|
|
211
199
|
@foreign_type ||= options[:foreign_type] || "#{name}_type"
|
|
212
200
|
end
|
|
@@ -274,6 +262,10 @@ module ActiveRecord
|
|
|
274
262
|
[self]
|
|
275
263
|
end
|
|
276
264
|
|
|
265
|
+
def nested?
|
|
266
|
+
false
|
|
267
|
+
end
|
|
268
|
+
|
|
277
269
|
# An array of arrays of conditions. Each item in the outside array corresponds to a reflection
|
|
278
270
|
# in the #chain. The inside arrays are simply conditions (and each condition may itself be
|
|
279
271
|
# a hash, array, arel predicate, etc...)
|
|
@@ -381,7 +373,7 @@ module ActiveRecord
|
|
|
381
373
|
delegate :foreign_key, :foreign_type, :association_foreign_key,
|
|
382
374
|
:active_record_primary_key, :type, :to => :source_reflection
|
|
383
375
|
|
|
384
|
-
# Gets the source of the through reflection.
|
|
376
|
+
# Gets the source of the through reflection. It checks both a singularized
|
|
385
377
|
# and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
|
|
386
378
|
#
|
|
387
379
|
# class Post < ActiveRecord::Base
|
|
@@ -469,7 +461,7 @@ module ActiveRecord
|
|
|
469
461
|
source_reflection.source_macro
|
|
470
462
|
end
|
|
471
463
|
|
|
472
|
-
# A through association is nested
|
|
464
|
+
# A through association is nested if there would be more than one join table
|
|
473
465
|
def nested?
|
|
474
466
|
chain.length > 2 || through_reflection.macro == :has_and_belongs_to_many
|
|
475
467
|
end
|
|
@@ -66,11 +66,14 @@ module ActiveRecord
|
|
|
66
66
|
records = relation.where(table[primary_key].gteq(start)).all
|
|
67
67
|
|
|
68
68
|
while records.any?
|
|
69
|
+
records_size = records.size
|
|
70
|
+
primary_key_offset = records.last.id
|
|
71
|
+
|
|
69
72
|
yield records
|
|
70
73
|
|
|
71
|
-
break if
|
|
74
|
+
break if records_size < batch_size
|
|
72
75
|
|
|
73
|
-
if primary_key_offset
|
|
76
|
+
if primary_key_offset
|
|
74
77
|
records = relation.where(table[primary_key].gt(primary_key_offset)).to_a
|
|
75
78
|
else
|
|
76
79
|
raise "Primary key not included in the custom select clause"
|