activerecord 3.2.22.5 → 4.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1024 -543
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -29
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +55 -44
- data/lib/active_record/aggregations.rb +40 -34
- data/lib/active_record/associations.rb +204 -276
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +30 -35
- data/lib/active_record/associations/association_scope.rb +40 -40
- data/lib/active_record/associations/belongs_to_association.rb +15 -2
- data/lib/active_record/associations/builder/association.rb +81 -28
- data/lib/active_record/associations/builder/belongs_to.rb +35 -57
- data/lib/active_record/associations/builder/collection_association.rb +54 -40
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +13 -50
- data/lib/active_record/associations/builder/singular_association.rb +13 -13
- data/lib/active_record/associations/collection_association.rb +92 -88
- data/lib/active_record/associations/collection_proxy.rb +913 -63
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +12 -10
- data/lib/active_record/associations/has_many_association.rb +35 -9
- data/lib/active_record/associations/has_many_through_association.rb +24 -14
- data/lib/active_record/associations/has_one_association.rb +33 -13
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_helper.rb +1 -11
- data/lib/active_record/associations/preloader.rb +14 -17
- data/lib/active_record/associations/preloader/association.rb +29 -33
- data/lib/active_record/associations/preloader/collection_association.rb +1 -1
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/through_association.rb +13 -17
- data/lib/active_record/associations/singular_association.rb +11 -11
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/attribute_assignment.rb +133 -153
- data/lib/active_record/attribute_methods.rb +196 -93
- data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
- data/lib/active_record/attribute_methods/dirty.rb +31 -28
- data/lib/active_record/attribute_methods/primary_key.rb +38 -30
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +62 -91
- data/lib/active_record/attribute_methods/serialization.rb +97 -66
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -45
- data/lib/active_record/attribute_methods/write.rb +32 -39
- data/lib/active_record/autosave_association.rb +56 -70
- data/lib/active_record/base.rb +53 -450
- data/lib/active_record/callbacks.rb +53 -18
- data/lib/active_record/coders/yaml_column.rb +11 -9
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +353 -197
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -131
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -3
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +101 -91
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +225 -96
- data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +99 -46
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +114 -36
- data/lib/active_record/connection_adapters/column.rb +46 -24
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +181 -64
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +132 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +347 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +158 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +448 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +454 -885
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -16
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +574 -13
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +428 -0
- data/lib/active_record/counter_cache.rb +106 -108
- data/lib/active_record/dynamic_matchers.rb +110 -63
- data/lib/active_record/errors.rb +25 -8
- data/lib/active_record/explain.rb +8 -58
- data/lib/active_record/explain_subscriber.rb +6 -3
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +146 -148
- data/lib/active_record/inheritance.rb +77 -59
- data/lib/active_record/integration.rb +5 -5
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +38 -42
- data/lib/active_record/locking/pessimistic.rb +4 -4
- data/lib/active_record/log_subscriber.rb +19 -9
- data/lib/active_record/migration.rb +318 -153
- data/lib/active_record/migration/command_recorder.rb +90 -31
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/model_schema.rb +69 -92
- data/lib/active_record/nested_attributes.rb +113 -148
- data/lib/active_record/null_relation.rb +65 -0
- data/lib/active_record/persistence.rb +188 -97
- data/lib/active_record/query_cache.rb +18 -36
- data/lib/active_record/querying.rb +19 -15
- data/lib/active_record/railtie.rb +91 -36
- data/lib/active_record/railties/console_sandbox.rb +0 -2
- data/lib/active_record/railties/controller_runtime.rb +2 -2
- data/lib/active_record/railties/databases.rake +90 -309
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +7 -3
- data/lib/active_record/reflection.rb +72 -56
- data/lib/active_record/relation.rb +241 -157
- data/lib/active_record/relation/batches.rb +25 -22
- data/lib/active_record/relation/calculations.rb +143 -121
- data/lib/active_record/relation/delegation.rb +96 -18
- data/lib/active_record/relation/finder_methods.rb +117 -183
- data/lib/active_record/relation/merger.rb +133 -0
- data/lib/active_record/relation/predicate_builder.rb +90 -42
- data/lib/active_record/relation/query_methods.rb +666 -136
- data/lib/active_record/relation/spawn_methods.rb +43 -150
- data/lib/active_record/result.rb +33 -6
- data/lib/active_record/sanitization.rb +24 -50
- data/lib/active_record/schema.rb +19 -12
- data/lib/active_record/schema_dumper.rb +31 -39
- data/lib/active_record/schema_migration.rb +36 -0
- data/lib/active_record/scoping.rb +0 -124
- data/lib/active_record/scoping/default.rb +48 -45
- data/lib/active_record/scoping/named.rb +74 -103
- data/lib/active_record/serialization.rb +6 -2
- data/lib/active_record/serializers/xml_serializer.rb +9 -15
- data/lib/active_record/store.rb +119 -15
- data/lib/active_record/tasks/database_tasks.rb +158 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +138 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
- data/lib/active_record/test_case.rb +61 -38
- data/lib/active_record/timestamp.rb +8 -9
- data/lib/active_record/transactions.rb +65 -51
- data/lib/active_record/validations.rb +17 -15
- data/lib/active_record/validations/associated.rb +20 -14
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +93 -52
- data/lib/active_record/version.rb +4 -4
- data/lib/rails/generators/active_record.rb +3 -5
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -7
- data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -3
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- metadata +53 -46
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/session_store.rb +0 -360
- data/lib/rails/generators/active_record/migration.rb +0 -15
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,49 +1,8 @@
|
|
1
|
-
require 'active_support/
|
1
|
+
require 'active_support/lazy_load_hooks'
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
module Explain
|
5
|
-
|
6
|
-
base.class_eval do
|
7
|
-
# If a query takes longer than these many seconds we log its query plan
|
8
|
-
# automatically. nil disables this feature.
|
9
|
-
class_attribute :auto_explain_threshold_in_seconds, :instance_writer => false
|
10
|
-
self.auto_explain_threshold_in_seconds = nil
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
# If the database adapter supports explain and auto explain is enabled,
|
15
|
-
# this method triggers EXPLAIN logging for the queries triggered by the
|
16
|
-
# block if it takes more than the threshold as a whole. That is, the
|
17
|
-
# threshold is not checked against each individual query, but against the
|
18
|
-
# duration of the entire block. This approach is convenient for relations.
|
19
|
-
|
20
|
-
#
|
21
|
-
# The available_queries_for_explain thread variable collects the queries
|
22
|
-
# to be explained. If the value is nil, it means queries are not being
|
23
|
-
# currently collected. A false value indicates collecting is turned
|
24
|
-
# off. Otherwise it is an array of queries.
|
25
|
-
def logging_query_plan # :nodoc:
|
26
|
-
return yield unless logger
|
27
|
-
|
28
|
-
threshold = auto_explain_threshold_in_seconds
|
29
|
-
current = Thread.current
|
30
|
-
if connection.supports_explain? && threshold && current[:available_queries_for_explain].nil?
|
31
|
-
begin
|
32
|
-
queries = current[:available_queries_for_explain] = []
|
33
|
-
start = Time.now
|
34
|
-
result = yield
|
35
|
-
logger.warn(exec_explain(queries)) if Time.now - start > threshold
|
36
|
-
result
|
37
|
-
ensure
|
38
|
-
current[:available_queries_for_explain] = nil
|
39
|
-
end
|
40
|
-
else
|
41
|
-
yield
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Relation#explain needs to be able to collect the queries regardless of
|
46
|
-
# whether auto explain is enabled. This method serves that purpose.
|
5
|
+
# Relation#explain needs to be able to collect the queries.
|
47
6
|
def collecting_queries_for_explain # :nodoc:
|
48
7
|
current = Thread.current
|
49
8
|
original, current[:available_queries_for_explain] = current[:available_queries_for_explain], []
|
@@ -56,7 +15,7 @@ module ActiveRecord
|
|
56
15
|
# Makes the adapter execute EXPLAIN for the tuples of queries and bindings.
|
57
16
|
# Returns a formatted string ready to be logged.
|
58
17
|
def exec_explain(queries) # :nodoc:
|
59
|
-
queries && queries.map do |sql, bind|
|
18
|
+
str = queries && queries.map do |sql, bind|
|
60
19
|
[].tap do |msg|
|
61
20
|
msg << "EXPLAIN for: #{sql}"
|
62
21
|
unless bind.empty?
|
@@ -66,21 +25,12 @@ module ActiveRecord
|
|
66
25
|
msg << connection.explain(sql, bind)
|
67
26
|
end.join("\n")
|
68
27
|
end.join("\n")
|
69
|
-
end
|
70
28
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
# As the name of the method suggests this only applies to automatic
|
77
|
-
# EXPLAINs, manual calls to +ActiveRecord::Relation#explain+ run.
|
78
|
-
def silence_auto_explain
|
79
|
-
current = Thread.current
|
80
|
-
original, current[:available_queries_for_explain] = current[:available_queries_for_explain], false
|
81
|
-
yield
|
82
|
-
ensure
|
83
|
-
current[:available_queries_for_explain] = original
|
29
|
+
# Overriding inspect to be more human readable, specially in the console.
|
30
|
+
def str.inspect
|
31
|
+
self
|
32
|
+
end
|
33
|
+
str
|
84
34
|
end
|
85
35
|
end
|
86
36
|
end
|
@@ -2,9 +2,12 @@ require 'active_support/notifications'
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
class ExplainSubscriber # :nodoc:
|
5
|
-
def
|
5
|
+
def start(name, id, payload)
|
6
|
+
# unused
|
7
|
+
end
|
8
|
+
|
9
|
+
def finish(name, id, payload)
|
6
10
|
if queries = Thread.current[:available_queries_for_explain]
|
7
|
-
payload = args.last
|
8
11
|
queries << payload.values_at(:sql, :binds) unless ignore_payload?(payload)
|
9
12
|
end
|
10
13
|
end
|
@@ -15,7 +18,7 @@ module ActiveRecord
|
|
15
18
|
# On the other hand, we want to monitor the performance of our real database
|
16
19
|
# queries, not the performance of the access to the query cache.
|
17
20
|
IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE)
|
18
|
-
EXPLAINED_SQLS = /\A\s*(select|update|delete|insert)
|
21
|
+
EXPLAINED_SQLS = /\A\s*(select|update|delete|insert)/i
|
19
22
|
def ignore_payload?(payload)
|
20
23
|
payload[:exception] || IGNORED_PAYLOADS.include?(payload[:name]) || payload[:sql] !~ EXPLAINED_SQLS
|
21
24
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
class FixtureSet
|
6
|
+
class File # :nodoc:
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
##
|
10
|
+
# Open a fixture file named +file+. When called with a block, the block
|
11
|
+
# is called with the filehandle and the filehandle is automatically closed
|
12
|
+
# when the block finishes.
|
13
|
+
def self.open(file)
|
14
|
+
x = new file
|
15
|
+
block_given? ? yield(x) : x
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(file)
|
19
|
+
@file = file
|
20
|
+
@rows = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def each(&block)
|
24
|
+
rows.each(&block)
|
25
|
+
end
|
26
|
+
|
27
|
+
RESCUE_ERRORS = [ ArgumentError, Psych::SyntaxError ] # :nodoc:
|
28
|
+
|
29
|
+
private
|
30
|
+
def rows
|
31
|
+
return @rows if @rows
|
32
|
+
|
33
|
+
begin
|
34
|
+
data = YAML.load(render(IO.read(@file)))
|
35
|
+
rescue *RESCUE_ERRORS => error
|
36
|
+
raise Fixture::FormatError, "a YAML error occurred parsing #{@file}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}", error.backtrace
|
37
|
+
end
|
38
|
+
@rows = data ? validate(data).to_a : []
|
39
|
+
end
|
40
|
+
|
41
|
+
def render(content)
|
42
|
+
ERB.new(content).result
|
43
|
+
end
|
44
|
+
|
45
|
+
# Validate our unmarshalled data.
|
46
|
+
def validate(data)
|
47
|
+
unless Hash === data || YAML::Omap === data
|
48
|
+
raise Fixture::FormatError, 'fixture is not a hash'
|
49
|
+
end
|
50
|
+
|
51
|
+
raise Fixture::FormatError unless data.all? { |name, row| Hash === row }
|
52
|
+
data
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,28 +1,14 @@
|
|
1
1
|
require 'erb'
|
2
|
-
|
3
|
-
begin
|
4
|
-
require 'psych'
|
5
|
-
rescue LoadError
|
6
|
-
end
|
7
|
-
|
8
2
|
require 'yaml'
|
9
3
|
require 'zlib'
|
10
4
|
require 'active_support/dependencies'
|
11
|
-
require '
|
12
|
-
require '
|
13
|
-
require 'active_support/core_ext/logger'
|
14
|
-
require 'active_support/ordered_hash'
|
15
|
-
require 'active_record/fixtures/file'
|
5
|
+
require 'active_record/fixture_set/file'
|
6
|
+
require 'active_record/errors'
|
16
7
|
|
17
|
-
|
8
|
+
module ActiveRecord
|
18
9
|
class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
|
19
10
|
end
|
20
|
-
else
|
21
|
-
class FixtureClassNotFound < StandardError #:nodoc:
|
22
|
-
end
|
23
|
-
end
|
24
11
|
|
25
|
-
module ActiveRecord
|
26
12
|
# \Fixtures are a way of organizing data that you want to test against; in short, sample data.
|
27
13
|
#
|
28
14
|
# They are stored in YAML files, one file per model, which are placed in the directory
|
@@ -96,7 +82,7 @@ module ActiveRecord
|
|
96
82
|
# end
|
97
83
|
#
|
98
84
|
# test "find_alt_method_2" do
|
99
|
-
# assert_equal "Ruby on Rails", @rubyonrails.
|
85
|
+
# assert_equal "Ruby on Rails", @rubyonrails.name
|
100
86
|
# end
|
101
87
|
#
|
102
88
|
# In order to use these methods to access fixtured data within your testcases, you must specify one of the
|
@@ -262,7 +248,7 @@ module ActiveRecord
|
|
262
248
|
#
|
263
249
|
# ### in fruit.rb
|
264
250
|
#
|
265
|
-
# belongs_to :eater, :
|
251
|
+
# belongs_to :eater, polymorphic: true
|
266
252
|
#
|
267
253
|
# ### in fruits.yml
|
268
254
|
#
|
@@ -364,8 +350,8 @@ module ActiveRecord
|
|
364
350
|
# to the rescue:
|
365
351
|
#
|
366
352
|
# george_reginald:
|
367
|
-
# monkey_id: <%= ActiveRecord::
|
368
|
-
# pirate_id: <%= ActiveRecord::
|
353
|
+
# monkey_id: <%= ActiveRecord::FixtureSet.identify(:reginald) %>
|
354
|
+
# pirate_id: <%= ActiveRecord::FixtureSet.identify(:george) %>
|
369
355
|
#
|
370
356
|
# == Support for YAML defaults
|
371
357
|
#
|
@@ -377,22 +363,38 @@ module ActiveRecord
|
|
377
363
|
#
|
378
364
|
# first:
|
379
365
|
# name: Smurf
|
380
|
-
# *DEFAULTS
|
366
|
+
# <<: *DEFAULTS
|
381
367
|
#
|
382
368
|
# second:
|
383
369
|
# name: Fraggle
|
384
|
-
# *DEFAULTS
|
370
|
+
# <<: *DEFAULTS
|
385
371
|
#
|
386
372
|
# Any fixture labeled "DEFAULTS" is safely ignored.
|
387
|
-
class
|
373
|
+
class FixtureSet
|
374
|
+
#--
|
375
|
+
# An instance of FixtureSet is normally stored in a single YAML file and possibly in a folder with the same name.
|
376
|
+
#++
|
377
|
+
|
388
378
|
MAX_ID = 2 ** 30 - 1
|
389
379
|
|
390
380
|
@@all_cached_fixtures = Hash.new { |h,k| h[k] = {} }
|
391
381
|
|
392
|
-
def self.find_table_name(
|
382
|
+
def self.find_table_name(fixture_set_name) # :nodoc:
|
383
|
+
ActiveSupport::Deprecation.warn(
|
384
|
+
"ActiveRecord::Fixtures.find_table_name is deprecated and shall be removed from future releases. Use ActiveRecord::Fixtures.default_fixture_model_name instead.")
|
385
|
+
default_fixture_model_name(fixture_set_name)
|
386
|
+
end
|
387
|
+
|
388
|
+
def self.default_fixture_model_name(fixture_set_name) # :nodoc:
|
393
389
|
ActiveRecord::Base.pluralize_table_names ?
|
394
|
-
|
395
|
-
|
390
|
+
fixture_set_name.singularize.camelize :
|
391
|
+
fixture_set_name.camelize
|
392
|
+
end
|
393
|
+
|
394
|
+
def self.default_fixture_table_name(fixture_set_name) # :nodoc:
|
395
|
+
"#{ ActiveRecord::Base.table_name_prefix }"\
|
396
|
+
"#{ fixture_set_name.tr('/', '_') }"\
|
397
|
+
"#{ ActiveRecord::Base.table_name_suffix }".to_sym
|
396
398
|
end
|
397
399
|
|
398
400
|
def self.reset_cache
|
@@ -419,11 +421,7 @@ module ActiveRecord
|
|
419
421
|
cache_for_connection(connection).update(fixtures_map)
|
420
422
|
end
|
421
423
|
|
422
|
-
|
423
|
-
# TODO:NOTE: in the next version, the __with_new_arity suffix and
|
424
|
-
# the method with the old arity will be removed.
|
425
|
-
#++
|
426
|
-
def self.instantiate_fixtures__with_new_arity(object, fixture_set, load_instances = true) # :nodoc:
|
424
|
+
def self.instantiate_fixtures(object, fixture_set, load_instances = true)
|
427
425
|
if load_instances
|
428
426
|
fixture_set.each do |fixture_name, fixture|
|
429
427
|
begin
|
@@ -435,79 +433,60 @@ module ActiveRecord
|
|
435
433
|
end
|
436
434
|
end
|
437
435
|
|
438
|
-
# The use with parameters <tt>(object, fixture_set_name, fixture_set, load_instances = true)</tt> is deprecated, +fixture_set_name+ parameter is not used.
|
439
|
-
# Use as:
|
440
|
-
#
|
441
|
-
# instantiate_fixtures(object, fixture_set, load_instances = true)
|
442
|
-
def self.instantiate_fixtures(object, fixture_set, load_instances = true, rails_3_2_compatibility_argument = true)
|
443
|
-
unless load_instances == true || load_instances == false
|
444
|
-
ActiveSupport::Deprecation.warn(
|
445
|
-
"ActiveRecord::Fixtures.instantiate_fixtures with parameters (object, fixture_set_name, fixture_set, load_instances = true) is deprecated and shall be removed from future releases. Use it with parameters (object, fixture_set, load_instances = true) instead (skip fixture_set_name).",
|
446
|
-
caller)
|
447
|
-
fixture_set = load_instances
|
448
|
-
load_instances = rails_3_2_compatibility_argument
|
449
|
-
end
|
450
|
-
instantiate_fixtures__with_new_arity(object, fixture_set, load_instances)
|
451
|
-
end
|
452
|
-
|
453
436
|
def self.instantiate_all_loaded_fixtures(object, load_instances = true)
|
454
437
|
all_loaded_fixtures.each_value do |fixture_set|
|
455
|
-
|
438
|
+
instantiate_fixtures(object, fixture_set, load_instances)
|
456
439
|
end
|
457
440
|
end
|
458
441
|
|
459
442
|
cattr_accessor :all_loaded_fixtures
|
460
443
|
self.all_loaded_fixtures = {}
|
461
444
|
|
462
|
-
def self.create_fixtures(fixtures_directory,
|
463
|
-
|
464
|
-
|
465
|
-
class_names[n.tr('/', '_').to_sym] = n.classify if n.include?('/')
|
466
|
-
}
|
445
|
+
def self.create_fixtures(fixtures_directory, fixture_set_names, class_names = {})
|
446
|
+
fixture_set_names = Array(fixture_set_names).map(&:to_s)
|
447
|
+
class_names = class_names.stringify_keys
|
467
448
|
|
468
449
|
# FIXME: Apparently JK uses this.
|
469
450
|
connection = block_given? ? yield : ActiveRecord::Base.connection
|
470
451
|
|
471
|
-
files_to_read =
|
472
|
-
fixture_is_cached?(connection,
|
452
|
+
files_to_read = fixture_set_names.reject { |fs_name|
|
453
|
+
fixture_is_cached?(connection, fs_name)
|
473
454
|
}
|
474
455
|
|
475
456
|
unless files_to_read.empty?
|
476
457
|
connection.disable_referential_integrity do
|
477
458
|
fixtures_map = {}
|
478
459
|
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
fixtures_map[path] = ActiveRecord::Fixtures.new(
|
460
|
+
fixture_sets = files_to_read.map do |fs_name|
|
461
|
+
fixtures_map[fs_name] = new( # ActiveRecord::FixtureSet.new
|
483
462
|
connection,
|
484
|
-
|
485
|
-
class_names[
|
486
|
-
::File.join(fixtures_directory,
|
463
|
+
fs_name,
|
464
|
+
class_names[fs_name] || default_fixture_model_name(fs_name),
|
465
|
+
::File.join(fixtures_directory, fs_name))
|
487
466
|
end
|
488
467
|
|
489
468
|
all_loaded_fixtures.update(fixtures_map)
|
490
469
|
|
491
470
|
connection.transaction(:requires_new => true) do
|
492
|
-
|
493
|
-
conn =
|
494
|
-
table_rows =
|
471
|
+
fixture_sets.each do |fs|
|
472
|
+
conn = fs.model_class.respond_to?(:connection) ? fs.model_class.connection : connection
|
473
|
+
table_rows = fs.table_rows
|
495
474
|
|
496
475
|
table_rows.keys.each do |table|
|
497
476
|
conn.delete "DELETE FROM #{conn.quote_table_name(table)}", 'Fixture Delete'
|
498
477
|
end
|
499
478
|
|
500
|
-
table_rows.each do |
|
479
|
+
table_rows.each do |fixture_set_name, rows|
|
501
480
|
rows.each do |row|
|
502
|
-
conn.insert_fixture(row,
|
481
|
+
conn.insert_fixture(row, fixture_set_name)
|
503
482
|
end
|
504
483
|
end
|
505
484
|
end
|
506
485
|
|
507
486
|
# Cap primary key sequences to max(pk).
|
508
487
|
if connection.respond_to?(:reset_pk_sequence!)
|
509
|
-
|
510
|
-
connection.reset_pk_sequence!(table_name
|
488
|
+
fixture_sets.each do |fs|
|
489
|
+
connection.reset_pk_sequence!(fs.table_name)
|
511
490
|
end
|
512
491
|
end
|
513
492
|
end
|
@@ -515,7 +494,7 @@ module ActiveRecord
|
|
515
494
|
cache_fixtures(connection, fixtures_map)
|
516
495
|
end
|
517
496
|
end
|
518
|
-
cached_fixtures(connection,
|
497
|
+
cached_fixtures(connection, fixture_set_names)
|
519
498
|
end
|
520
499
|
|
521
500
|
# Returns a consistent, platform-independent identifier for +label+.
|
@@ -526,25 +505,24 @@ module ActiveRecord
|
|
526
505
|
|
527
506
|
attr_reader :table_name, :name, :fixtures, :model_class
|
528
507
|
|
529
|
-
def initialize(connection,
|
530
|
-
@
|
531
|
-
@
|
532
|
-
@
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
@fixtures = ActiveSupport::OrderedHash.new
|
537
|
-
@table_name = "#{ActiveRecord::Base.table_name_prefix}#{@table_name}#{ActiveRecord::Base.table_name_suffix}"
|
538
|
-
|
539
|
-
# Should be an AR::Base type class
|
540
|
-
if class_name.is_a?(Class)
|
541
|
-
@table_name = class_name.table_name
|
542
|
-
@connection = class_name.connection
|
543
|
-
@model_class = class_name
|
508
|
+
def initialize(connection, name, class_name, path)
|
509
|
+
@fixtures = {} # Ordered hash
|
510
|
+
@name = name
|
511
|
+
@path = path
|
512
|
+
|
513
|
+
if class_name.is_a?(Class) # TODO: Should be an AR::Base type class, or any?
|
514
|
+
@model_class = class_name
|
544
515
|
else
|
545
|
-
@model_class
|
516
|
+
@model_class = class_name.constantize rescue nil
|
546
517
|
end
|
547
518
|
|
519
|
+
@connection = ( model_class.respond_to?(:connection) ?
|
520
|
+
model_class.connection : connection )
|
521
|
+
|
522
|
+
@table_name = ( model_class.respond_to?(:table_name) ?
|
523
|
+
model_class.table_name :
|
524
|
+
self.class.default_fixture_table_name(name) )
|
525
|
+
|
548
526
|
read_fixture_files
|
549
527
|
end
|
550
528
|
|
@@ -582,19 +560,19 @@ module ActiveRecord
|
|
582
560
|
if model_class && model_class < ActiveRecord::Base
|
583
561
|
# fill in timestamp columns if they aren't specified and the model is set to record_timestamps
|
584
562
|
if model_class.record_timestamps
|
585
|
-
timestamp_column_names.each do |
|
586
|
-
row[
|
563
|
+
timestamp_column_names.each do |c_name|
|
564
|
+
row[c_name] = now unless row.key?(c_name)
|
587
565
|
end
|
588
566
|
end
|
589
567
|
|
590
568
|
# interpolate the fixture label
|
591
569
|
row.each do |key, value|
|
592
|
-
row[key] = label if value
|
570
|
+
row[key] = label if value == "$LABEL"
|
593
571
|
end
|
594
572
|
|
595
573
|
# generate a primary key if necessary
|
596
574
|
if has_primary_key_column? && !row.include?(primary_key_name)
|
597
|
-
row[primary_key_name] = ActiveRecord::
|
575
|
+
row[primary_key_name] = ActiveRecord::FixtureSet.identify(label)
|
598
576
|
end
|
599
577
|
|
600
578
|
# If STI is used, find the correct subclass for association reflection
|
@@ -617,15 +595,15 @@ module ActiveRecord
|
|
617
595
|
row[association.foreign_type] = $1
|
618
596
|
end
|
619
597
|
|
620
|
-
row[fk_name] = ActiveRecord::
|
598
|
+
row[fk_name] = ActiveRecord::FixtureSet.identify(value)
|
621
599
|
end
|
622
600
|
when :has_and_belongs_to_many
|
623
601
|
if (targets = row.delete(association.name.to_s))
|
624
602
|
targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
|
625
|
-
table_name = association.
|
603
|
+
table_name = association.join_table
|
626
604
|
rows[table_name].concat targets.map { |target|
|
627
605
|
{ association.foreign_key => row[primary_key_name],
|
628
|
-
association.association_foreign_key => ActiveRecord::
|
606
|
+
association.association_foreign_key => ActiveRecord::FixtureSet.identify(target) }
|
629
607
|
}
|
630
608
|
end
|
631
609
|
end
|
@@ -661,25 +639,31 @@ module ActiveRecord
|
|
661
639
|
end
|
662
640
|
|
663
641
|
def read_fixture_files
|
664
|
-
yaml_files = Dir["#{@
|
642
|
+
yaml_files = Dir["#{@path}/**/*.yml"].select { |f|
|
665
643
|
::File.file?(f)
|
666
644
|
} + [yaml_file_path]
|
667
645
|
|
668
646
|
yaml_files.each do |file|
|
669
|
-
|
670
|
-
fh.each do |
|
671
|
-
fixtures[
|
647
|
+
FixtureSet::File.open(file) do |fh|
|
648
|
+
fh.each do |fixture_name, row|
|
649
|
+
fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class)
|
672
650
|
end
|
673
651
|
end
|
674
652
|
end
|
675
653
|
end
|
676
654
|
|
677
655
|
def yaml_file_path
|
678
|
-
"#{@
|
656
|
+
"#{@path}.yml"
|
679
657
|
end
|
680
658
|
|
681
659
|
end
|
682
660
|
|
661
|
+
#--
|
662
|
+
# Deprecate 'Fixtures' in favor of 'FixtureSet'.
|
663
|
+
#++
|
664
|
+
# :nodoc:
|
665
|
+
Fixtures = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('ActiveRecord::Fixtures', 'ActiveRecord::FixtureSet')
|
666
|
+
|
683
667
|
class Fixture #:nodoc:
|
684
668
|
include Enumerable
|
685
669
|
|
@@ -732,7 +716,7 @@ module ActiveRecord
|
|
732
716
|
class_attribute :fixture_table_names
|
733
717
|
class_attribute :fixture_class_names
|
734
718
|
class_attribute :use_transactional_fixtures
|
735
|
-
class_attribute :use_instantiated_fixtures
|
719
|
+
class_attribute :use_instantiated_fixtures # true, false, or :no_instances
|
736
720
|
class_attribute :pre_loaded_fixtures
|
737
721
|
|
738
722
|
self.fixture_table_names = []
|
@@ -740,27 +724,42 @@ module ActiveRecord
|
|
740
724
|
self.use_instantiated_fixtures = false
|
741
725
|
self.pre_loaded_fixtures = false
|
742
726
|
|
743
|
-
self.fixture_class_names = Hash.new do |h,
|
744
|
-
h[
|
727
|
+
self.fixture_class_names = Hash.new do |h, fixture_set_name|
|
728
|
+
h[fixture_set_name] = ActiveRecord::FixtureSet.default_fixture_model_name(fixture_set_name)
|
745
729
|
end
|
746
730
|
end
|
747
731
|
|
748
732
|
module ClassMethods
|
733
|
+
# Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
|
734
|
+
#
|
735
|
+
# Examples:
|
736
|
+
#
|
737
|
+
# set_fixture_class some_fixture: SomeModel,
|
738
|
+
# 'namespaced/fixture' => Another::Model
|
739
|
+
#
|
740
|
+
# The keys must be the fixture names, that coincide with the short paths to the fixture files.
|
741
|
+
#--
|
742
|
+
# It is also possible to pass the class name instead of the class:
|
743
|
+
# set_fixture_class 'some_fixture' => 'SomeModel'
|
744
|
+
# I think this option is redundant, i propose to deprecate it.
|
745
|
+
# Isn't it easier to always pass the class itself?
|
746
|
+
# (2011-12-20 alexeymuranov)
|
747
|
+
#++
|
749
748
|
def set_fixture_class(class_names = {})
|
750
|
-
self.fixture_class_names = self.fixture_class_names.merge(class_names)
|
749
|
+
self.fixture_class_names = self.fixture_class_names.merge(class_names.stringify_keys)
|
751
750
|
end
|
752
751
|
|
753
|
-
def fixtures(*
|
754
|
-
if
|
755
|
-
|
756
|
-
|
752
|
+
def fixtures(*fixture_set_names)
|
753
|
+
if fixture_set_names.first == :all
|
754
|
+
fixture_set_names = Dir["#{fixture_path}/**/*.{yml}"]
|
755
|
+
fixture_set_names.map! { |f| f[(fixture_path.size + 1)..-5] }
|
757
756
|
else
|
758
|
-
|
757
|
+
fixture_set_names = fixture_set_names.flatten.map { |n| n.to_s }
|
759
758
|
end
|
760
759
|
|
761
|
-
self.fixture_table_names |=
|
762
|
-
require_fixture_classes(
|
763
|
-
setup_fixture_accessors(
|
760
|
+
self.fixture_table_names |= fixture_set_names
|
761
|
+
require_fixture_classes(fixture_set_names)
|
762
|
+
setup_fixture_accessors(fixture_set_names)
|
764
763
|
end
|
765
764
|
|
766
765
|
def try_to_load_dependency(file_name)
|
@@ -775,40 +774,45 @@ module ActiveRecord
|
|
775
774
|
end
|
776
775
|
end
|
777
776
|
|
778
|
-
def require_fixture_classes(
|
779
|
-
|
780
|
-
|
777
|
+
def require_fixture_classes(fixture_set_names = nil)
|
778
|
+
if fixture_set_names
|
779
|
+
fixture_set_names = fixture_set_names.map { |n| n.to_s }
|
780
|
+
else
|
781
|
+
fixture_set_names = fixture_table_names
|
782
|
+
end
|
783
|
+
|
784
|
+
fixture_set_names.each do |file_name|
|
781
785
|
file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names
|
782
786
|
try_to_load_dependency(file_name)
|
783
787
|
end
|
784
788
|
end
|
785
789
|
|
786
|
-
def setup_fixture_accessors(
|
787
|
-
|
790
|
+
def setup_fixture_accessors(fixture_set_names = nil)
|
791
|
+
fixture_set_names = Array(fixture_set_names || fixture_table_names)
|
788
792
|
methods = Module.new do
|
789
|
-
|
790
|
-
|
793
|
+
fixture_set_names.each do |fs_name|
|
794
|
+
fs_name = fs_name.to_s
|
795
|
+
accessor_name = fs_name.tr('/', '_').to_sym
|
791
796
|
|
792
|
-
define_method(
|
793
|
-
force_reload =
|
797
|
+
define_method(accessor_name) do |*fixture_names|
|
798
|
+
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
794
799
|
|
795
|
-
@fixture_cache[
|
800
|
+
@fixture_cache[fs_name] ||= {}
|
796
801
|
|
797
|
-
instances =
|
798
|
-
|
802
|
+
instances = fixture_names.map do |f_name|
|
803
|
+
f_name = f_name.to_s
|
804
|
+
@fixture_cache[fs_name].delete(f_name) if force_reload
|
799
805
|
|
800
|
-
if @loaded_fixtures[
|
801
|
-
|
802
|
-
@fixture_cache[fixture_name][fixture] ||= @loaded_fixtures[fixture_name][fixture.to_s].find
|
803
|
-
end
|
806
|
+
if @loaded_fixtures[fs_name][f_name]
|
807
|
+
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
|
804
808
|
else
|
805
|
-
raise StandardError, "No fixture
|
809
|
+
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
|
806
810
|
end
|
807
811
|
end
|
808
812
|
|
809
813
|
instances.size == 1 ? instances.first : instances
|
810
814
|
end
|
811
|
-
private
|
815
|
+
private accessor_name
|
812
816
|
end
|
813
817
|
end
|
814
818
|
include methods
|
@@ -831,7 +835,7 @@ module ActiveRecord
|
|
831
835
|
end
|
832
836
|
|
833
837
|
def setup_fixtures
|
834
|
-
return
|
838
|
+
return if ActiveRecord::Base.configurations.blank?
|
835
839
|
|
836
840
|
if pre_loaded_fixtures && !use_transactional_fixtures
|
837
841
|
raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
|
@@ -851,13 +855,11 @@ module ActiveRecord
|
|
851
855
|
end
|
852
856
|
@fixture_connections = enlist_fixture_connections
|
853
857
|
@fixture_connections.each do |connection|
|
854
|
-
connection.
|
855
|
-
connection.transaction_joinable = false
|
856
|
-
connection.begin_db_transaction
|
858
|
+
connection.begin_transaction joinable: false
|
857
859
|
end
|
858
860
|
# Load fixtures for every test.
|
859
861
|
else
|
860
|
-
ActiveRecord::
|
862
|
+
ActiveRecord::FixtureSet.reset_cache
|
861
863
|
@@already_loaded_fixtures[self.class] = nil
|
862
864
|
@loaded_fixtures = load_fixtures
|
863
865
|
end
|
@@ -867,32 +869,28 @@ module ActiveRecord
|
|
867
869
|
end
|
868
870
|
|
869
871
|
def teardown_fixtures
|
870
|
-
return
|
871
|
-
|
872
|
-
unless run_in_transaction?
|
873
|
-
ActiveRecord::Fixtures.reset_cache
|
874
|
-
end
|
872
|
+
return if ActiveRecord::Base.configurations.blank?
|
875
873
|
|
876
874
|
# Rollback changes if a transaction is active.
|
877
875
|
if run_in_transaction?
|
878
876
|
@fixture_connections.each do |connection|
|
879
|
-
if connection.
|
880
|
-
connection.rollback_db_transaction
|
881
|
-
connection.decrement_open_transactions
|
882
|
-
end
|
877
|
+
connection.rollback_transaction if connection.transaction_open?
|
883
878
|
end
|
884
879
|
@fixture_connections.clear
|
880
|
+
else
|
881
|
+
ActiveRecord::FixtureSet.reset_cache
|
885
882
|
end
|
883
|
+
|
886
884
|
ActiveRecord::Base.clear_active_connections!
|
887
885
|
end
|
888
886
|
|
889
887
|
def enlist_fixture_connections
|
890
|
-
ActiveRecord::Base.connection_handler.
|
888
|
+
ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
|
891
889
|
end
|
892
890
|
|
893
891
|
private
|
894
892
|
def load_fixtures
|
895
|
-
fixtures = ActiveRecord::
|
893
|
+
fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
|
896
894
|
Hash[fixtures.map { |f| [f.name, f] }]
|
897
895
|
end
|
898
896
|
|
@@ -901,16 +899,16 @@ module ActiveRecord
|
|
901
899
|
|
902
900
|
def instantiate_fixtures
|
903
901
|
if pre_loaded_fixtures
|
904
|
-
raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::
|
902
|
+
raise RuntimeError, 'Load fixtures before instantiating them.' if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
|
905
903
|
unless @@required_fixture_classes
|
906
|
-
self.class.require_fixture_classes ActiveRecord::
|
904
|
+
self.class.require_fixture_classes ActiveRecord::FixtureSet.all_loaded_fixtures.keys
|
907
905
|
@@required_fixture_classes = true
|
908
906
|
end
|
909
|
-
ActiveRecord::
|
907
|
+
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
|
910
908
|
else
|
911
909
|
raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
|
912
910
|
@loaded_fixtures.each_value do |fixture_set|
|
913
|
-
ActiveRecord::
|
911
|
+
ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
|
914
912
|
end
|
915
913
|
end
|
916
914
|
end
|