activerecord 4.0.0.beta1 → 4.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +573 -30
- data/README.rdoc +3 -3
- data/lib/active_record.rb +8 -2
- data/lib/active_record/associations.rb +16 -9
- data/lib/active_record/associations/association.rb +8 -6
- data/lib/active_record/associations/association_scope.rb +2 -1
- data/lib/active_record/associations/belongs_to_association.rb +2 -2
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
- data/lib/active_record/associations/builder/belongs_to.rb +37 -5
- data/lib/active_record/associations/collection_association.rb +38 -14
- data/lib/active_record/associations/collection_proxy.rb +18 -15
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +3 -3
- data/lib/active_record/associations/has_many_association.rb +4 -3
- data/lib/active_record/associations/has_many_through_association.rb +1 -1
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +29 -8
- data/lib/active_record/associations/join_dependency/join_association.rb +26 -6
- data/lib/active_record/associations/join_dependency/join_base.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_part.rb +6 -6
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/preloader/has_many_through.rb +6 -2
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/attribute_assignment.rb +5 -5
- data/lib/active_record/attribute_methods.rb +20 -5
- data/lib/active_record/attribute_methods/dirty.rb +5 -1
- data/lib/active_record/attribute_methods/primary_key.rb +1 -1
- data/lib/active_record/attribute_methods/serialization.rb +9 -2
- data/lib/active_record/autosave_association.rb +19 -5
- data/lib/active_record/base.rb +3 -3
- data/lib/active_record/callbacks.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +8 -13
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +3 -9
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +2 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +2 -8
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +60 -61
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +13 -2
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +291 -153
- data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +92 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +55 -29
- data/lib/active_record/connection_adapters/column.rb +4 -4
- data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -3
- data/lib/active_record/connection_adapters/mysql_adapter.rb +5 -5
- data/lib/active_record/connection_adapters/postgresql/cast.rb +22 -2
- data/lib/active_record/connection_adapters/postgresql/oid.rb +25 -6
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -13
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +50 -9
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +53 -24
- data/lib/active_record/connection_adapters/schema_cache.rb +35 -7
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -5
- data/lib/active_record/connection_handling.rb +7 -7
- data/lib/active_record/core.rb +43 -8
- data/lib/active_record/counter_cache.rb +2 -1
- data/lib/active_record/errors.rb +11 -10
- data/lib/active_record/explain.rb +9 -7
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +3 -2
- data/lib/active_record/fixture_set/file.rb +1 -2
- data/lib/active_record/fixtures.rb +13 -7
- data/lib/active_record/inheritance.rb +12 -4
- data/lib/active_record/integration.rb +3 -3
- data/lib/active_record/locking/optimistic.rb +2 -2
- data/lib/active_record/log_subscriber.rb +2 -2
- data/lib/active_record/migration.rb +69 -21
- data/lib/active_record/model_schema.rb +1 -1
- data/lib/active_record/nested_attributes.rb +98 -46
- data/lib/active_record/persistence.rb +3 -3
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +18 -4
- data/lib/active_record/railties/console_sandbox.rb +3 -2
- data/lib/active_record/railties/controller_runtime.rb +2 -1
- data/lib/active_record/railties/databases.rake +38 -80
- data/lib/active_record/reflection.rb +36 -3
- data/lib/active_record/relation.rb +18 -8
- data/lib/active_record/relation/calculations.rb +10 -5
- data/lib/active_record/relation/delegation.rb +3 -5
- data/lib/active_record/relation/finder_methods.rb +27 -14
- data/lib/active_record/relation/merger.rb +30 -2
- data/lib/active_record/relation/predicate_builder.rb +1 -6
- data/lib/active_record/relation/query_methods.rb +113 -16
- data/lib/active_record/runtime_registry.rb +17 -0
- data/lib/active_record/schema_dumper.rb +5 -1
- data/lib/active_record/schema_migration.rb +8 -5
- data/lib/active_record/scoping.rb +56 -2
- data/lib/active_record/scoping/default.rb +12 -11
- data/lib/active_record/scoping/named.rb +7 -3
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/statement_cache.rb +26 -0
- data/lib/active_record/tasks/database_tasks.rb +55 -10
- data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +7 -2
- data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
- data/lib/active_record/timestamp.rb +6 -0
- data/lib/active_record/transactions.rb +7 -3
- data/lib/active_record/validations.rb +1 -2
- data/lib/active_record/validations/uniqueness.rb +7 -3
- data/lib/active_record/version.rb +7 -6
- data/lib/rails/generators/active_record/migration/migration_generator.rb +9 -2
- data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +4 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +4 -1
- metadata +17 -12
- data/examples/associations.png +0 -0
@@ -51,7 +51,7 @@ module ActiveRecord
|
|
51
51
|
# how this "single-table" inheritance mapping is implemented.
|
52
52
|
def instantiate(record, column_types = {})
|
53
53
|
klass = discriminate_class_for_record(record)
|
54
|
-
column_types = klass.decorate_columns(column_types)
|
54
|
+
column_types = klass.decorate_columns(column_types.dup)
|
55
55
|
klass.allocate.init_with('attributes' => record, 'column_types' => column_types)
|
56
56
|
end
|
57
57
|
|
@@ -410,7 +410,7 @@ module ActiveRecord
|
|
410
410
|
def relation_for_destroy
|
411
411
|
pk = self.class.primary_key
|
412
412
|
column = self.class.columns_hash[pk]
|
413
|
-
substitute = connection.substitute_at(column, 0)
|
413
|
+
substitute = self.class.connection.substitute_at(column, 0)
|
414
414
|
|
415
415
|
relation = self.class.unscoped.where(
|
416
416
|
self.class.arel_table[pk].eq(substitute))
|
@@ -443,7 +443,7 @@ module ActiveRecord
|
|
443
443
|
real_column = db_columns_with_values[i].first
|
444
444
|
bind_attrs[column] = klass.connection.substitute_at(real_column, i)
|
445
445
|
end
|
446
|
-
stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.compile_update(bind_attrs)
|
446
|
+
stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id_was || id)).arel.compile_update(bind_attrs)
|
447
447
|
klass.connection.update stmt, 'SQL', db_columns_with_values
|
448
448
|
end
|
449
449
|
end
|
@@ -8,7 +8,7 @@ module ActiveRecord
|
|
8
8
|
delegate :find_each, :find_in_batches, :to => :all
|
9
9
|
delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins,
|
10
10
|
:where, :preload, :eager_load, :includes, :from, :lock, :readonly,
|
11
|
-
:having, :create_with, :uniq, :references, :none, :to => :all
|
11
|
+
:having, :create_with, :uniq, :distinct, :references, :none, :unscope, :to => :all
|
12
12
|
delegate :count, :average, :minimum, :maximum, :sum, :calculate, :pluck, :ids, :to => :all
|
13
13
|
|
14
14
|
# Executes a custom SQL query against your database and returns all the results. The results will
|
@@ -36,6 +36,20 @@ module ActiveRecord
|
|
36
36
|
|
37
37
|
rake_tasks do
|
38
38
|
require "active_record/base"
|
39
|
+
|
40
|
+
ActiveRecord::Tasks::DatabaseTasks.env = Rails.env
|
41
|
+
ActiveRecord::Tasks::DatabaseTasks.db_dir = Rails.application.config.paths["db"].first
|
42
|
+
ActiveRecord::Tasks::DatabaseTasks.seed_loader = Rails.application
|
43
|
+
ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration
|
44
|
+
ActiveRecord::Tasks::DatabaseTasks.migrations_paths = Rails.application.paths['db/migrate'].to_a
|
45
|
+
ActiveRecord::Tasks::DatabaseTasks.fixtures_path = File.join Rails.root, 'test', 'fixtures'
|
46
|
+
|
47
|
+
if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
|
48
|
+
if engine.paths['db/migrate'].existent
|
49
|
+
ActiveRecord::Tasks::DatabaseTasks.migrations_paths += engine.paths['db/migrate'].to_a
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
39
53
|
load "active_record/railties/databases.rake"
|
40
54
|
end
|
41
55
|
|
@@ -49,7 +63,7 @@ module ActiveRecord
|
|
49
63
|
Rails.logger.extend ActiveSupport::Logger.broadcast console
|
50
64
|
end
|
51
65
|
|
52
|
-
runner do
|
66
|
+
runner do
|
53
67
|
require "active_record/base"
|
54
68
|
end
|
55
69
|
|
@@ -64,7 +78,7 @@ module ActiveRecord
|
|
64
78
|
ActiveSupport.on_load(:active_record) { self.logger ||= ::Rails.logger }
|
65
79
|
end
|
66
80
|
|
67
|
-
initializer "active_record.migration_error" do
|
81
|
+
initializer "active_record.migration_error" do
|
68
82
|
if config.active_record.delete(:migration_error) == :page_load
|
69
83
|
config.app_middleware.insert_after "::ActionDispatch::Callbacks",
|
70
84
|
"ActiveRecord::Migration::CheckPending"
|
@@ -152,13 +166,13 @@ module ActiveRecord
|
|
152
166
|
# and then establishes the connection.
|
153
167
|
initializer "active_record.initialize_database" do |app|
|
154
168
|
ActiveSupport.on_load(:active_record) do
|
155
|
-
self.configurations = app.config.database_configuration
|
169
|
+
self.configurations = app.config.database_configuration || {}
|
156
170
|
establish_connection
|
157
171
|
end
|
158
172
|
end
|
159
173
|
|
160
174
|
# Expose database runtime to controller for logging.
|
161
|
-
initializer "active_record.log_runtime" do
|
175
|
+
initializer "active_record.log_runtime" do
|
162
176
|
require "active_record/railties/controller_runtime"
|
163
177
|
ActiveSupport.on_load(:action_controller) do
|
164
178
|
include ActiveRecord::Railties::ControllerRuntime
|
@@ -21,9 +21,10 @@ module ActiveRecord
|
|
21
21
|
def cleanup_view_runtime
|
22
22
|
if ActiveRecord::Base.connected?
|
23
23
|
db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
|
24
|
+
self.db_runtime = (db_runtime || 0) + db_rt_before_render
|
24
25
|
runtime = super
|
25
26
|
db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime
|
26
|
-
self.db_runtime
|
27
|
+
self.db_runtime += db_rt_after_render
|
27
28
|
runtime - db_rt_after_render
|
28
29
|
else
|
29
30
|
super
|
@@ -2,14 +2,8 @@ require 'active_record'
|
|
2
2
|
|
3
3
|
db_namespace = namespace :db do
|
4
4
|
task :load_config do
|
5
|
-
ActiveRecord::Base.configurations =
|
6
|
-
ActiveRecord::Migrator.migrations_paths =
|
7
|
-
|
8
|
-
if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
|
9
|
-
if engine.paths['db/migrate'].existent
|
10
|
-
ActiveRecord::Migrator.migrations_paths += engine.paths['db/migrate'].to_a
|
11
|
-
end
|
12
|
-
end
|
5
|
+
ActiveRecord::Base.configurations = ActiveRecord::Tasks::DatabaseTasks.database_configuration || {}
|
6
|
+
ActiveRecord::Migrator.migrations_paths = ActiveRecord::Tasks::DatabaseTasks.migrations_paths
|
13
7
|
end
|
14
8
|
|
15
9
|
namespace :create do
|
@@ -156,7 +150,7 @@ db_namespace = namespace :db do
|
|
156
150
|
begin
|
157
151
|
puts ActiveRecord::Tasks::DatabaseTasks.collation_current
|
158
152
|
rescue NoMethodError
|
159
|
-
$stderr.puts 'Sorry, your database adapter is not supported yet
|
153
|
+
$stderr.puts 'Sorry, your database adapter is not supported yet. Feel free to submit a patch.'
|
160
154
|
end
|
161
155
|
end
|
162
156
|
|
@@ -166,11 +160,11 @@ db_namespace = namespace :db do
|
|
166
160
|
end
|
167
161
|
|
168
162
|
# desc "Raises an error if there are pending migrations"
|
169
|
-
task :abort_if_pending_migrations =>
|
163
|
+
task :abort_if_pending_migrations => :environment do
|
170
164
|
pending_migrations = ActiveRecord::Migrator.open(ActiveRecord::Migrator.migrations_paths).pending_migrations
|
171
165
|
|
172
166
|
if pending_migrations.any?
|
173
|
-
puts "You have #{pending_migrations.size} pending migrations:"
|
167
|
+
puts "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}"
|
174
168
|
pending_migrations.each do |pending_migration|
|
175
169
|
puts ' %4d %s' % [pending_migration.version, pending_migration.name]
|
176
170
|
end
|
@@ -184,7 +178,7 @@ db_namespace = namespace :db do
|
|
184
178
|
desc 'Load the seed data from db/seeds.rb'
|
185
179
|
task :seed do
|
186
180
|
db_namespace['abort_if_pending_migrations'].invoke
|
187
|
-
|
181
|
+
ActiveRecord::Tasks::DatabaseTasks.load_seed
|
188
182
|
end
|
189
183
|
|
190
184
|
namespace :fixtures do
|
@@ -192,7 +186,15 @@ db_namespace = namespace :db do
|
|
192
186
|
task :load => [:environment, :load_config] do
|
193
187
|
require 'active_record/fixtures'
|
194
188
|
|
195
|
-
base_dir
|
189
|
+
base_dir = if ENV['FIXTURES_PATH']
|
190
|
+
STDERR.puts "Using FIXTURES_PATH env variable is deprecated, please use " +
|
191
|
+
"ActiveRecord::Tasks::DatabaseTasks.fixtures_path = '/path/to/fixtures' " +
|
192
|
+
"instead."
|
193
|
+
File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
|
194
|
+
else
|
195
|
+
ActiveRecord::Tasks::DatabaseTasks.fixtures_path
|
196
|
+
end
|
197
|
+
|
196
198
|
fixtures_dir = File.join [base_dir, ENV['FIXTURES_DIR']].compact
|
197
199
|
|
198
200
|
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }).each do |fixture_file|
|
@@ -209,7 +211,16 @@ db_namespace = namespace :db do
|
|
209
211
|
|
210
212
|
puts %Q(The fixture ID for "#{label}" is #{ActiveRecord::FixtureSet.identify(label)}.) if label
|
211
213
|
|
212
|
-
base_dir =
|
214
|
+
base_dir = if ENV['FIXTURES_PATH']
|
215
|
+
STDERR.puts "Using FIXTURES_PATH env variable is deprecated, please use " +
|
216
|
+
"ActiveRecord::Tasks::DatabaseTasks.fixtures_path = '/path/to/fixtures' " +
|
217
|
+
"instead."
|
218
|
+
File.join [Rails.root, ENV['FIXTURES_PATH'] || %w{test fixtures}].flatten
|
219
|
+
else
|
220
|
+
ActiveRecord::Tasks::DatabaseTasks.fixtures_path
|
221
|
+
end
|
222
|
+
|
223
|
+
|
213
224
|
Dir["#{base_dir}/**/*.yml"].each do |file|
|
214
225
|
if data = YAML::load(ERB.new(IO.read(file)).result)
|
215
226
|
data.keys.each do |key|
|
@@ -228,7 +239,7 @@ db_namespace = namespace :db do
|
|
228
239
|
desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR'
|
229
240
|
task :dump => [:environment, :load_config] do
|
230
241
|
require 'active_record/schema_dumper'
|
231
|
-
filename = ENV['SCHEMA'] ||
|
242
|
+
filename = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb')
|
232
243
|
File.open(filename, "w:utf-8") do |file|
|
233
244
|
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
|
234
245
|
end
|
@@ -237,11 +248,11 @@ db_namespace = namespace :db do
|
|
237
248
|
|
238
249
|
desc 'Load a schema.rb file into the database'
|
239
250
|
task :load => [:environment, :load_config] do
|
240
|
-
file = ENV['SCHEMA'] ||
|
251
|
+
file = ENV['SCHEMA'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, 'schema.rb')
|
241
252
|
if File.exists?(file)
|
242
253
|
load(file)
|
243
254
|
else
|
244
|
-
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}
|
255
|
+
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.}
|
245
256
|
end
|
246
257
|
end
|
247
258
|
|
@@ -253,7 +264,7 @@ db_namespace = namespace :db do
|
|
253
264
|
desc 'Create a db/schema_cache.dump file.'
|
254
265
|
task :dump => [:environment, :load_config] do
|
255
266
|
con = ActiveRecord::Base.connection
|
256
|
-
filename = File.join(
|
267
|
+
filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump")
|
257
268
|
|
258
269
|
con.schema_cache.clear!
|
259
270
|
con.tables.each { |table| con.schema_cache.add(table) }
|
@@ -262,7 +273,7 @@ db_namespace = namespace :db do
|
|
262
273
|
|
263
274
|
desc 'Clear a db/schema_cache.dump file.'
|
264
275
|
task :clear => [:environment, :load_config] do
|
265
|
-
filename = File.join(
|
276
|
+
filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump")
|
266
277
|
FileUtils.rm(filename) if File.exists?(filename)
|
267
278
|
end
|
268
279
|
end
|
@@ -270,32 +281,11 @@ db_namespace = namespace :db do
|
|
270
281
|
end
|
271
282
|
|
272
283
|
namespace :structure do
|
273
|
-
def set_firebird_env(config)
|
274
|
-
ENV['ISC_USER'] = config['username'].to_s if config['username']
|
275
|
-
ENV['ISC_PASSWORD'] = config['password'].to_s if config['password']
|
276
|
-
end
|
277
|
-
|
278
|
-
def firebird_db_string(config)
|
279
|
-
FireRuby::Database.db_string_for(config.symbolize_keys)
|
280
|
-
end
|
281
|
-
|
282
284
|
desc 'Dump the database structure to db/structure.sql. Specify another file with DB_STRUCTURE=db/my_structure.sql'
|
283
285
|
task :dump => [:environment, :load_config] do
|
284
|
-
filename = ENV['DB_STRUCTURE'] || File.join(
|
286
|
+
filename = ENV['DB_STRUCTURE'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
|
285
287
|
current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
|
286
|
-
|
287
|
-
when 'oci', 'oracle'
|
288
|
-
ActiveRecord::Base.establish_connection(current_config)
|
289
|
-
File.open(filename, "w:utf-8") { |f| f << ActiveRecord::Base.connection.structure_dump }
|
290
|
-
when 'sqlserver'
|
291
|
-
`smoscript -s #{current_config['host']} -d #{current_config['database']} -u #{current_config['username']} -p #{current_config['password']} -f #{filename} -A -U`
|
292
|
-
when "firebird"
|
293
|
-
set_firebird_env(current_config)
|
294
|
-
db_string = firebird_db_string(current_config)
|
295
|
-
sh "isql -a #{db_string} > #{filename}"
|
296
|
-
else
|
297
|
-
ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
|
298
|
-
end
|
288
|
+
ActiveRecord::Tasks::DatabaseTasks.structure_dump(current_config, filename)
|
299
289
|
|
300
290
|
if ActiveRecord::Base.connection.supports_migrations?
|
301
291
|
File.open(filename, "a") do |f|
|
@@ -307,23 +297,9 @@ db_namespace = namespace :db do
|
|
307
297
|
|
308
298
|
# desc "Recreate the databases from the structure.sql file"
|
309
299
|
task :load => [:environment, :load_config] do
|
300
|
+
filename = ENV['DB_STRUCTURE'] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "structure.sql")
|
310
301
|
current_config = ActiveRecord::Tasks::DatabaseTasks.current_config
|
311
|
-
|
312
|
-
case current_config['adapter']
|
313
|
-
when 'sqlserver'
|
314
|
-
`sqlcmd -S #{current_config['host']} -d #{current_config['database']} -U #{current_config['username']} -P #{current_config['password']} -i #{filename}`
|
315
|
-
when 'oci', 'oracle'
|
316
|
-
ActiveRecord::Base.establish_connection(current_config)
|
317
|
-
IO.read(filename).split(";\n\n").each do |ddl|
|
318
|
-
ActiveRecord::Base.connection.execute(ddl)
|
319
|
-
end
|
320
|
-
when 'firebird'
|
321
|
-
set_firebird_env(current_config)
|
322
|
-
db_string = firebird_db_string(current_config)
|
323
|
-
sh "isql -i #{filename} #{db_string}"
|
324
|
-
else
|
325
|
-
ActiveRecord::Tasks::DatabaseTasks.structure_load(current_config, filename)
|
326
|
-
end
|
302
|
+
ActiveRecord::Tasks::DatabaseTasks.structure_load(current_config, filename)
|
327
303
|
end
|
328
304
|
|
329
305
|
task :load_if_sql => ['db:create', :environment] do
|
@@ -378,29 +354,11 @@ db_namespace = namespace :db do
|
|
378
354
|
|
379
355
|
# desc "Empty the test database"
|
380
356
|
task :purge => [:environment, :load_config] do
|
381
|
-
|
382
|
-
case abcs['test']['adapter']
|
383
|
-
when 'sqlserver'
|
384
|
-
test = abcs.deep_dup['test']
|
385
|
-
test_database = test['database']
|
386
|
-
test['database'] = 'master'
|
387
|
-
ActiveRecord::Base.establish_connection(test)
|
388
|
-
ActiveRecord::Base.connection.recreate_database!(test_database)
|
389
|
-
when "oci", "oracle"
|
390
|
-
ActiveRecord::Base.establish_connection(:test)
|
391
|
-
ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
|
392
|
-
ActiveRecord::Base.connection.execute(ddl)
|
393
|
-
end
|
394
|
-
when 'firebird'
|
395
|
-
ActiveRecord::Base.establish_connection(:test)
|
396
|
-
ActiveRecord::Base.connection.recreate_database!
|
397
|
-
else
|
398
|
-
ActiveRecord::Tasks::DatabaseTasks.purge abcs['test']
|
399
|
-
end
|
357
|
+
ActiveRecord::Tasks::DatabaseTasks.purge ActiveRecord::Base.configurations['test']
|
400
358
|
end
|
401
359
|
|
402
360
|
# desc 'Check for pending migrations and load the test schema'
|
403
|
-
task :prepare
|
361
|
+
task :prepare do
|
404
362
|
unless ActiveRecord::Base.configurations.blank?
|
405
363
|
db_namespace['test:load'].invoke
|
406
364
|
end
|
@@ -426,7 +384,7 @@ namespace :railties do
|
|
426
384
|
puts "NOTE: Migration #{migration.basename} from #{name} has been skipped. Migration with the same name already exists."
|
427
385
|
end
|
428
386
|
|
429
|
-
on_copy = Proc.new do |name, migration
|
387
|
+
on_copy = Proc.new do |name, migration|
|
430
388
|
puts "Copied migration #{migration.basename} from #{name}"
|
431
389
|
end
|
432
390
|
|
@@ -436,5 +394,5 @@ namespace :railties do
|
|
436
394
|
end
|
437
395
|
end
|
438
396
|
|
439
|
-
task 'test:prepare' => 'db:test:prepare'
|
397
|
+
task 'test:prepare' => ['db:test:prepare', 'db:test:load', 'db:abort_if_pending_migrations']
|
440
398
|
|
@@ -75,8 +75,13 @@ module ActiveRecord
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
#
|
78
|
+
# Base class for AggregateReflection and AssociationReflection. Objects of
|
79
79
|
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
|
80
|
+
#
|
81
|
+
# MacroReflection
|
82
|
+
# AggregateReflection
|
83
|
+
# AssociationReflection
|
84
|
+
# ThroughReflection
|
80
85
|
class MacroReflection
|
81
86
|
# Returns the name of the macro.
|
82
87
|
#
|
@@ -401,6 +406,16 @@ module ActiveRecord
|
|
401
406
|
# has_many :tags, through: :taggings
|
402
407
|
# end
|
403
408
|
#
|
409
|
+
# class Tagging < ActiveRecord::Base
|
410
|
+
# belongs_to :post
|
411
|
+
# belongs_to :tag
|
412
|
+
# end
|
413
|
+
#
|
414
|
+
# tags_reflection = Post.reflect_on_association(:tags)
|
415
|
+
#
|
416
|
+
# taggings_reflection = tags_reflection.source_reflection
|
417
|
+
# # => <ActiveRecord::Reflection::AssociationReflection: @macro=:belongs_to, @name=:tag, @active_record=Tagging, @plural_name="tags">
|
418
|
+
#
|
404
419
|
def source_reflection
|
405
420
|
@source_reflection ||= source_reflection_names.collect { |name| through_reflection.klass.reflect_on_association(name) }.compact.first
|
406
421
|
end
|
@@ -426,6 +441,17 @@ module ActiveRecord
|
|
426
441
|
# The chain is built by recursively calling #chain on the source reflection and the through
|
427
442
|
# reflection. The base case for the recursion is a normal association, which just returns
|
428
443
|
# [self] as its #chain.
|
444
|
+
#
|
445
|
+
# class Post < ActiveRecord::Base
|
446
|
+
# has_many :taggings
|
447
|
+
# has_many :tags, through: :taggings
|
448
|
+
# end
|
449
|
+
#
|
450
|
+
# tags_reflection = Post.reflect_on_association(:tags)
|
451
|
+
# tags_reflection.chain
|
452
|
+
# # => [<ActiveRecord::Reflection::ThroughReflection: @macro=:has_many, @name=:tags, @options={:through=>:taggings}, @active_record=Post>,
|
453
|
+
# <ActiveRecord::Reflection::AssociationReflection: @macro=:has_many, @name=:taggings, @options={}, @active_record=Post>]
|
454
|
+
#
|
429
455
|
def chain
|
430
456
|
@chain ||= begin
|
431
457
|
chain = source_reflection.chain + through_reflection.chain
|
@@ -496,9 +522,16 @@ module ActiveRecord
|
|
496
522
|
source_reflection.options[:primary_key] || primary_key(klass || self.klass)
|
497
523
|
end
|
498
524
|
|
499
|
-
# Gets an array of possible <tt>:through</tt> source reflection names
|
525
|
+
# Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form.
|
526
|
+
#
|
527
|
+
# class Post < ActiveRecord::Base
|
528
|
+
# has_many :taggings
|
529
|
+
# has_many :tags, through: :taggings
|
530
|
+
# end
|
500
531
|
#
|
501
|
-
#
|
532
|
+
# tags_reflection = Post.reflect_on_association(:tags)
|
533
|
+
# tags_reflection.source_reflection_names
|
534
|
+
# # => [:tag, :tags]
|
502
535
|
#
|
503
536
|
def source_reflection_names
|
504
537
|
@source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }
|
@@ -10,14 +10,14 @@ module ActiveRecord
|
|
10
10
|
:extending]
|
11
11
|
|
12
12
|
SINGLE_VALUE_METHODS = [:limit, :offset, :lock, :readonly, :from, :reordering,
|
13
|
-
:reverse_order, :
|
13
|
+
:reverse_order, :distinct, :create_with, :uniq]
|
14
14
|
|
15
15
|
VALUE_METHODS = MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS
|
16
16
|
|
17
17
|
include FinderMethods, Calculations, SpawnMethods, QueryMethods, Batches, Explain, Delegation
|
18
18
|
|
19
19
|
attr_reader :table, :klass, :loaded
|
20
|
-
attr_accessor :default_scoped
|
20
|
+
attr_accessor :default_scoped, :proxy_association
|
21
21
|
alias :model :klass
|
22
22
|
alias :loaded? :loaded
|
23
23
|
alias :default_scoped? :default_scoped
|
@@ -188,8 +188,7 @@ module ActiveRecord
|
|
188
188
|
# Please see further details in the
|
189
189
|
# {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain].
|
190
190
|
def explain
|
191
|
-
|
192
|
-
exec_explain(queries)
|
191
|
+
exec_explain(collecting_queries_for_explain { exec_queries })
|
193
192
|
end
|
194
193
|
|
195
194
|
# Converts relation objects to Array.
|
@@ -236,8 +235,9 @@ module ActiveRecord
|
|
236
235
|
# Scope all queries to the current scope.
|
237
236
|
#
|
238
237
|
# Comment.where(post_id: 1).scoping do
|
239
|
-
# Comment.first
|
238
|
+
# Comment.first
|
240
239
|
# end
|
240
|
+
# # => SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = 1 ORDER BY "comments"."id" ASC LIMIT 1
|
241
241
|
#
|
242
242
|
# Please check unscoped if you want to remove all previous scopes (including
|
243
243
|
# the default_scope) during the execution of a block.
|
@@ -506,6 +506,12 @@ module ActiveRecord
|
|
506
506
|
includes_values & joins_values
|
507
507
|
end
|
508
508
|
|
509
|
+
# +uniq+ and +uniq!+ are silently deprecated. +uniq_value+ delegates to +distinct_value+
|
510
|
+
# to maintain backwards compatibility. Use +distinct_value+ instead.
|
511
|
+
def uniq_value
|
512
|
+
distinct_value
|
513
|
+
end
|
514
|
+
|
509
515
|
# Compares two relations for equality.
|
510
516
|
def ==(other)
|
511
517
|
case other
|
@@ -589,21 +595,25 @@ module ActiveRecord
|
|
589
595
|
|
590
596
|
if (references_values - joined_tables).any?
|
591
597
|
true
|
592
|
-
elsif
|
598
|
+
elsif !ActiveRecord::Base.disable_implicit_join_references &&
|
599
|
+
(string_tables - joined_tables).any?
|
593
600
|
ActiveSupport::Deprecation.warn(
|
594
601
|
"It looks like you are eager loading table(s) (one of: #{string_tables.join(', ')}) " \
|
595
602
|
"that are referenced in a string SQL snippet. For example: \n" \
|
596
603
|
"\n" \
|
597
604
|
" Post.includes(:comments).where(\"comments.title = 'foo'\")\n" \
|
598
605
|
"\n" \
|
599
|
-
"Currently, Active Record
|
606
|
+
"Currently, Active Record recognizes the table in the string, and knows to JOIN the " \
|
600
607
|
"comments table to the query, rather than loading comments in a separate query. " \
|
601
608
|
"However, doing this without writing a full-blown SQL parser is inherently flawed. " \
|
602
609
|
"Since we don't want to write an SQL parser, we are removing this functionality. " \
|
603
610
|
"From now on, you must explicitly tell Active Record when you are referencing a table " \
|
604
611
|
"from a string:\n" \
|
605
612
|
"\n" \
|
606
|
-
" Post.includes(:comments).where(\"comments.title = 'foo'\").references(:comments)\n\
|
613
|
+
" Post.includes(:comments).where(\"comments.title = 'foo'\").references(:comments)\n" \
|
614
|
+
"\n" \
|
615
|
+
"If you don't rely on implicit join references you can disable the feature entirely " \
|
616
|
+
"by setting `config.active_record.disable_implicit_join_references = true`."
|
607
617
|
)
|
608
618
|
true
|
609
619
|
else
|