activerecord 2.2.3 → 2.3.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +438 -396
- data/Rakefile +4 -2
- data/lib/active_record.rb +46 -43
- data/lib/active_record/association_preload.rb +34 -19
- data/lib/active_record/associations.rb +193 -251
- data/lib/active_record/associations/association_collection.rb +38 -21
- data/lib/active_record/associations/association_proxy.rb +11 -4
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +2 -2
- data/lib/active_record/associations/has_many_association.rb +2 -2
- data/lib/active_record/associations/has_many_through_association.rb +8 -8
- data/lib/active_record/associations/has_one_association.rb +11 -2
- data/lib/active_record/attribute_methods.rb +1 -0
- data/lib/active_record/autosave_association.rb +349 -0
- data/lib/active_record/base.rb +292 -106
- data/lib/active_record/batches.rb +73 -0
- data/lib/active_record/calculations.rb +34 -16
- data/lib/active_record/callbacks.rb +37 -8
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +16 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +3 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +103 -15
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +28 -25
- data/lib/active_record/connection_adapters/abstract_adapter.rb +29 -5
- data/lib/active_record/connection_adapters/mysql_adapter.rb +50 -21
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +26 -41
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +41 -21
- data/lib/active_record/dirty.rb +1 -1
- data/lib/active_record/dynamic_scope_match.rb +25 -0
- data/lib/active_record/fixtures.rb +193 -198
- data/lib/active_record/locale/en.yml +1 -1
- data/lib/active_record/locking/optimistic.rb +33 -0
- data/lib/active_record/migration.rb +8 -2
- data/lib/active_record/named_scope.rb +13 -6
- data/lib/active_record/nested_attributes.rb +329 -0
- data/lib/active_record/query_cache.rb +25 -13
- data/lib/active_record/reflection.rb +6 -1
- data/lib/active_record/schema_dumper.rb +2 -0
- data/lib/active_record/serialization.rb +3 -1
- data/lib/active_record/serializers/json_serializer.rb +19 -0
- data/lib/active_record/serializers/xml_serializer.rb +28 -13
- data/lib/active_record/session_store.rb +318 -0
- data/lib/active_record/test_case.rb +15 -9
- data/lib/active_record/timestamp.rb +2 -2
- data/lib/active_record/transactions.rb +58 -8
- data/lib/active_record/validations.rb +29 -24
- data/lib/active_record/version.rb +2 -2
- data/test/cases/ar_schema_test.rb +0 -1
- data/test/cases/associations/belongs_to_associations_test.rb +35 -131
- data/test/cases/associations/cascaded_eager_loading_test.rb +8 -0
- data/test/cases/associations/eager_load_nested_include_test.rb +29 -0
- data/test/cases/associations/eager_test.rb +137 -7
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +45 -7
- data/test/cases/associations/has_many_associations_test.rb +110 -149
- data/test/cases/associations/has_many_through_associations_test.rb +39 -7
- data/test/cases/associations/has_one_associations_test.rb +39 -92
- data/test/cases/associations/has_one_through_associations_test.rb +34 -3
- data/test/cases/associations/inner_join_association_test.rb +0 -5
- data/test/cases/associations/join_model_test.rb +5 -7
- data/test/cases/attribute_methods_test.rb +13 -1
- data/test/cases/autosave_association_test.rb +901 -0
- data/test/cases/base_test.rb +41 -21
- data/test/cases/batches_test.rb +61 -0
- data/test/cases/calculations_test.rb +37 -17
- data/test/cases/callbacks_test.rb +43 -5
- data/test/cases/connection_pool_test.rb +25 -0
- data/test/cases/copy_table_test_sqlite.rb +11 -0
- data/test/cases/datatype_test_postgresql.rb +1 -0
- data/test/cases/defaults_test.rb +37 -26
- data/test/cases/dirty_test.rb +26 -2
- data/test/cases/finder_test.rb +79 -44
- data/test/cases/fixtures_test.rb +15 -19
- data/test/cases/helper.rb +26 -19
- data/test/cases/inheritance_test.rb +2 -2
- data/test/cases/json_serialization_test.rb +1 -1
- data/test/cases/locking_test.rb +23 -5
- data/test/cases/method_scoping_test.rb +126 -3
- data/test/cases/migration_test.rb +253 -237
- data/test/cases/named_scope_test.rb +73 -3
- data/test/cases/nested_attributes_test.rb +509 -0
- data/test/cases/query_cache_test.rb +0 -4
- data/test/cases/reflection_test.rb +13 -3
- data/test/cases/reload_models_test.rb +3 -1
- data/test/cases/repair_helper.rb +50 -0
- data/test/cases/schema_dumper_test.rb +0 -1
- data/test/cases/transactions_test.rb +177 -12
- data/test/cases/validations_i18n_test.rb +288 -294
- data/test/cases/validations_test.rb +230 -180
- data/test/cases/xml_serialization_test.rb +19 -1
- data/test/fixtures/fixture_database.sqlite3 +0 -0
- data/test/fixtures/fixture_database_2.sqlite3 +0 -0
- data/test/fixtures/member_types.yml +6 -0
- data/test/fixtures/members.yml +3 -1
- data/test/fixtures/people.yml +10 -1
- data/test/fixtures/toys.yml +4 -0
- data/test/models/author.rb +1 -2
- data/test/models/bird.rb +3 -0
- data/test/models/category.rb +1 -0
- data/test/models/company.rb +3 -0
- data/test/models/developer.rb +12 -0
- data/test/models/event.rb +3 -0
- data/test/models/member.rb +1 -0
- data/test/models/member_detail.rb +1 -0
- data/test/models/member_type.rb +3 -0
- data/test/models/owner.rb +2 -1
- data/test/models/parrot.rb +2 -0
- data/test/models/person.rb +6 -0
- data/test/models/pet.rb +2 -1
- data/test/models/pirate.rb +55 -1
- data/test/models/post.rb +6 -0
- data/test/models/project.rb +1 -0
- data/test/models/reply.rb +6 -0
- data/test/models/ship.rb +8 -1
- data/test/models/ship_part.rb +5 -0
- data/test/models/topic.rb +13 -1
- data/test/models/toy.rb +4 -0
- data/test/schema/schema.rb +35 -2
- metadata +70 -9
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
data/lib/active_record/dirty.rb
CHANGED
@@ -174,7 +174,7 @@ module ActiveRecord
|
|
174
174
|
alias_attribute_without_dirty(new_name, old_name)
|
175
175
|
DIRTY_SUFFIXES.each do |suffix|
|
176
176
|
module_eval <<-STR, __FILE__, __LINE__+1
|
177
|
-
def #{new_name}#{suffix}; self.#{old_name}#{suffix}; end
|
177
|
+
def #{new_name}#{suffix}; self.#{old_name}#{suffix}; end # def subject_changed?; self.title_changed?; end
|
178
178
|
STR
|
179
179
|
end
|
180
180
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
class DynamicScopeMatch
|
3
|
+
def self.match(method)
|
4
|
+
ds_match = self.new(method)
|
5
|
+
ds_match.scope ? ds_match : nil
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(method)
|
9
|
+
@scope = true
|
10
|
+
case method.to_s
|
11
|
+
when /^scoped_by_([_a-zA-Z]\w*)$/
|
12
|
+
names = $1
|
13
|
+
else
|
14
|
+
@scope = nil
|
15
|
+
end
|
16
|
+
@attribute_names = names && names.split('_and_')
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :scope, :attribute_names
|
20
|
+
|
21
|
+
def scope?
|
22
|
+
!@scope.nil?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'erb'
|
2
2
|
require 'yaml'
|
3
3
|
require 'csv'
|
4
|
+
require 'active_support/dependencies'
|
4
5
|
require 'active_support/test_case'
|
5
6
|
|
6
7
|
if RUBY_VERSION < '1.9'
|
@@ -20,13 +21,17 @@ else
|
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
23
|
-
# Fixtures are a way of organizing data that you want to test against; in short, sample data.
|
24
|
+
# Fixtures are a way of organizing data that you want to test against; in short, sample data.
|
25
|
+
#
|
26
|
+
# = Fixture formats
|
27
|
+
#
|
28
|
+
# Fixtures come in 3 flavors:
|
24
29
|
#
|
25
30
|
# 1. YAML fixtures
|
26
31
|
# 2. CSV fixtures
|
27
32
|
# 3. Single-file fixtures
|
28
33
|
#
|
29
|
-
#
|
34
|
+
# == YAML fixtures
|
30
35
|
#
|
31
36
|
# This type of fixture is in YAML format and the preferred default. YAML is a file format which describes data structures
|
32
37
|
# in a non-verbose, human-readable format. It ships with Ruby 1.8.1+.
|
@@ -64,9 +69,9 @@ end
|
|
64
69
|
# parent_id: 1
|
65
70
|
# title: Child
|
66
71
|
#
|
67
|
-
#
|
72
|
+
# == CSV fixtures
|
68
73
|
#
|
69
|
-
# Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored
|
74
|
+
# Fixtures can also be kept in the Comma Separated Value (CSV) format. Akin to YAML fixtures, CSV fixtures are stored
|
70
75
|
# in a single file, but instead end with the <tt>.csv</tt> file extension
|
71
76
|
# (Rails example: <tt><your-rails-app>/test/fixtures/web_sites.csv</tt>).
|
72
77
|
#
|
@@ -89,7 +94,7 @@ end
|
|
89
94
|
# Most databases and spreadsheets support exporting to CSV format, so this is a great format for you to choose if you
|
90
95
|
# have existing data somewhere already.
|
91
96
|
#
|
92
|
-
#
|
97
|
+
# == Single-file fixtures
|
93
98
|
#
|
94
99
|
# This type of fixture was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats.
|
95
100
|
# Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory
|
@@ -112,65 +117,53 @@ end
|
|
112
117
|
# name => Ruby on Rails
|
113
118
|
# url => http://www.rubyonrails.org
|
114
119
|
#
|
115
|
-
# = Using
|
120
|
+
# = Using fixtures in testcases
|
116
121
|
#
|
117
122
|
# Since fixtures are a testing construct, we use them in our unit and functional tests. There are two ways to use the
|
118
123
|
# fixtures, but first let's take a look at a sample unit test:
|
119
124
|
#
|
120
|
-
# require '
|
125
|
+
# require 'test_helper'
|
121
126
|
#
|
122
127
|
# class WebSiteTest < ActiveSupport::TestCase
|
123
|
-
#
|
128
|
+
# test "web_site_count" do
|
124
129
|
# assert_equal 2, WebSite.count
|
125
130
|
# end
|
126
131
|
# end
|
127
132
|
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
# ...
|
132
|
-
# class WebSiteTest < ActiveSupport::TestCase
|
133
|
-
# fixtures :web_sites # add more by separating the symbols with commas
|
134
|
-
# ...
|
135
|
-
#
|
136
|
-
# By adding a "fixtures" method to the test case and passing it a list of symbols (only one is shown here though), we trigger
|
137
|
-
# the testing environment to automatically load the appropriate fixtures into the database before each test.
|
133
|
+
# By default, the <tt>test_helper module</tt> will load all of your fixtures into your test database, so this test will succeed.
|
134
|
+
# The testing environment will automatically load the all fixtures into the database before each test.
|
138
135
|
# To ensure consistent data, the environment deletes the fixtures before running the load.
|
139
136
|
#
|
140
|
-
# In addition to being available in the database, the
|
141
|
-
#
|
142
|
-
#
|
143
|
-
#
|
144
|
-
# On top of that, each record is automatically "found" (using <tt>Model.find(id)</tt>) and placed in the instance variable of its name.
|
145
|
-
# So for the YAML fixtures, we'd get <tt>@rubyonrails</tt> and <tt>@google</tt>, which could be interrogated using regular Active Record semantics:
|
137
|
+
# In addition to being available in the database, the fixture's data may also be accessed by
|
138
|
+
# using a special dynamic method, which has the same name as the model, and accepts the
|
139
|
+
# name of the fixture to instantiate:
|
146
140
|
#
|
147
|
-
#
|
148
|
-
#
|
149
|
-
# assert_equal @web_sites["rubyonrails"]["name"], @rubyonrails.name
|
141
|
+
# test "find" do
|
142
|
+
# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
|
150
143
|
# end
|
151
144
|
#
|
152
|
-
#
|
153
|
-
# "http://www.rubyonrails.org" and <tt>@web_sites["google"]["name"]</tt> would return "Google". The same fixtures, but loaded
|
154
|
-
# from a CSV fixture file, would be accessible via <tt>@web_sites["web_site_1"]["name"] == "Ruby on Rails"</tt> and have the individual
|
155
|
-
# fixtures available as instance variables <tt>@web_site_1</tt> and <tt>@web_site_2</tt>.
|
145
|
+
# Alternatively, you may enable auto-instantiation of the fixture data. For instance, take the following tests:
|
156
146
|
#
|
157
|
-
#
|
147
|
+
# test "find_alt_method_1" do
|
148
|
+
# assert_equal "Ruby on Rails", @web_sites['rubyonrails']['name']
|
149
|
+
# end
|
158
150
|
#
|
159
|
-
#
|
160
|
-
#
|
151
|
+
# test "find_alt_method_2" do
|
152
|
+
# assert_equal "Ruby on Rails", @rubyonrails.news
|
153
|
+
# end
|
161
154
|
#
|
162
|
-
#
|
163
|
-
#
|
155
|
+
# In order to use these methods to access fixtured data within your testcases, you must specify one of the
|
156
|
+
# following in your <tt>ActiveSupport::TestCase</tt>-derived class:
|
164
157
|
#
|
165
|
-
#
|
166
|
-
#
|
167
|
-
# model, and accepts the name of the fixture to instantiate:
|
158
|
+
# - to fully enable instantiated fixtures (enable alternate methods #1 and #2 above)
|
159
|
+
# self.use_instantiated_fixtures = true
|
168
160
|
#
|
169
|
-
#
|
161
|
+
# - create only the hash for the fixtures, do not 'find' each instance (enable alternate method #1 only)
|
162
|
+
# self.use_instantiated_fixtures = :no_instances
|
170
163
|
#
|
171
|
-
#
|
172
|
-
#
|
173
|
-
#
|
164
|
+
# Using either of these alternate methods incurs a performance hit, as the fixtured data must be fully
|
165
|
+
# traversed in the database to create the fixture hash and/or instance variables. This is expensive for
|
166
|
+
# large sets of fixtured data.
|
174
167
|
#
|
175
168
|
# = Dynamic fixtures with ERb
|
176
169
|
#
|
@@ -193,21 +186,17 @@ end
|
|
193
186
|
# = Transactional fixtures
|
194
187
|
#
|
195
188
|
# TestCases can use begin+rollback to isolate their changes to the database instead of having to delete+insert for every test case.
|
196
|
-
# They can also turn off auto-instantiation of fixture data since the feature is costly and often unused.
|
197
189
|
#
|
198
190
|
# class FooTest < ActiveSupport::TestCase
|
199
191
|
# self.use_transactional_fixtures = true
|
200
|
-
# self.use_instantiated_fixtures = false
|
201
|
-
#
|
202
|
-
# fixtures :foos
|
203
192
|
#
|
204
|
-
#
|
193
|
+
# test "godzilla" do
|
205
194
|
# assert !Foo.find(:all).empty?
|
206
195
|
# Foo.destroy_all
|
207
196
|
# assert Foo.find(:all).empty?
|
208
197
|
# end
|
209
198
|
#
|
210
|
-
#
|
199
|
+
# test "godzilla aftermath" do
|
211
200
|
# assert !Foo.find(:all).empty?
|
212
201
|
# end
|
213
202
|
# end
|
@@ -219,24 +208,25 @@ end
|
|
219
208
|
# access to fixture data for every table that has been loaded through fixtures (depending on the value of +use_instantiated_fixtures+)
|
220
209
|
#
|
221
210
|
# When *not* to use transactional fixtures:
|
222
|
-
#
|
223
|
-
#
|
224
|
-
#
|
225
|
-
#
|
226
|
-
#
|
211
|
+
#
|
212
|
+
# 1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit,
|
213
|
+
# particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify
|
214
|
+
# the results of your transaction until Active Record supports nested transactions or savepoints (in progress).
|
215
|
+
# 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
|
216
|
+
# Use InnoDB, MaxDB, or NDB instead.
|
227
217
|
#
|
228
218
|
# = Advanced YAML Fixtures
|
229
219
|
#
|
230
220
|
# YAML fixtures that don't specify an ID get some extra features:
|
231
221
|
#
|
232
|
-
# * Stable, autogenerated
|
222
|
+
# * Stable, autogenerated IDs
|
233
223
|
# * Label references for associations (belongs_to, has_one, has_many)
|
234
224
|
# * HABTM associations as inline lists
|
235
225
|
# * Autofilled timestamp columns
|
236
226
|
# * Fixture label interpolation
|
237
227
|
# * Support for YAML defaults
|
238
228
|
#
|
239
|
-
# == Stable, autogenerated
|
229
|
+
# == Stable, autogenerated IDs
|
240
230
|
#
|
241
231
|
# Here, have a monkey fixture:
|
242
232
|
#
|
@@ -291,7 +281,7 @@ end
|
|
291
281
|
#
|
292
282
|
# Add a few more monkeys and pirates and break this into multiple files,
|
293
283
|
# and it gets pretty hard to keep track of what's going on. Let's
|
294
|
-
# use labels instead of
|
284
|
+
# use labels instead of IDs:
|
295
285
|
#
|
296
286
|
# ### in pirates.yml
|
297
287
|
#
|
@@ -515,7 +505,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
|
|
515
505
|
|
516
506
|
all_loaded_fixtures.update(fixtures_map)
|
517
507
|
|
518
|
-
connection.transaction(
|
508
|
+
connection.transaction(:requires_new => true) do
|
519
509
|
fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
|
520
510
|
fixtures.each { |fixture| fixture.insert_fixtures }
|
521
511
|
|
@@ -813,186 +803,191 @@ class Fixture #:nodoc:
|
|
813
803
|
end
|
814
804
|
end
|
815
805
|
|
816
|
-
module
|
817
|
-
module
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
class << self
|
838
|
-
def set_fixture_class(class_names = {})
|
839
|
-
self.fixture_class_names = self.fixture_class_names.merge(class_names)
|
840
|
-
end
|
806
|
+
module ActiveRecord
|
807
|
+
module TestFixtures
|
808
|
+
def self.included(base)
|
809
|
+
base.class_eval do
|
810
|
+
setup :setup_fixtures
|
811
|
+
teardown :teardown_fixtures
|
812
|
+
|
813
|
+
superclass_delegating_accessor :fixture_path
|
814
|
+
superclass_delegating_accessor :fixture_table_names
|
815
|
+
superclass_delegating_accessor :fixture_class_names
|
816
|
+
superclass_delegating_accessor :use_transactional_fixtures
|
817
|
+
superclass_delegating_accessor :use_instantiated_fixtures # true, false, or :no_instances
|
818
|
+
superclass_delegating_accessor :pre_loaded_fixtures
|
819
|
+
|
820
|
+
self.fixture_table_names = []
|
821
|
+
self.use_transactional_fixtures = false
|
822
|
+
self.use_instantiated_fixtures = true
|
823
|
+
self.pre_loaded_fixtures = false
|
824
|
+
|
825
|
+
self.fixture_class_names = {}
|
826
|
+
end
|
841
827
|
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
828
|
+
base.extend ClassMethods
|
829
|
+
end
|
830
|
+
|
831
|
+
module ClassMethods
|
832
|
+
def set_fixture_class(class_names = {})
|
833
|
+
self.fixture_class_names = self.fixture_class_names.merge(class_names)
|
834
|
+
end
|
849
835
|
|
850
|
-
|
851
|
-
|
852
|
-
|
836
|
+
def fixtures(*table_names)
|
837
|
+
if table_names.first == :all
|
838
|
+
table_names = Dir["#{fixture_path}/*.yml"] + Dir["#{fixture_path}/*.csv"]
|
839
|
+
table_names.map! { |f| File.basename(f).split('.')[0..-2].join('.') }
|
840
|
+
else
|
841
|
+
table_names = table_names.flatten.map { |n| n.to_s }
|
853
842
|
end
|
854
843
|
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
844
|
+
self.fixture_table_names |= table_names
|
845
|
+
require_fixture_classes(table_names)
|
846
|
+
setup_fixture_accessors(table_names)
|
847
|
+
end
|
859
848
|
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
849
|
+
def try_to_load_dependency(file_name)
|
850
|
+
require_dependency file_name
|
851
|
+
rescue LoadError => e
|
852
|
+
# Let's hope the developer has included it himself
|
853
|
+
|
854
|
+
# Let's warn in case this is a subdependency, otherwise
|
855
|
+
# subdependency error messages are totally cryptic
|
856
|
+
if ActiveRecord::Base.logger
|
857
|
+
ActiveRecord::Base.logger.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
|
865
858
|
end
|
859
|
+
end
|
866
860
|
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
end
|
861
|
+
def require_fixture_classes(table_names = nil)
|
862
|
+
(table_names || fixture_table_names).each do |table_name|
|
863
|
+
file_name = table_name.to_s
|
864
|
+
file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names
|
865
|
+
try_to_load_dependency(file_name)
|
873
866
|
end
|
867
|
+
end
|
874
868
|
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
869
|
+
def setup_fixture_accessors(table_names = nil)
|
870
|
+
table_names = [table_names] if table_names && !table_names.respond_to?(:each)
|
871
|
+
(table_names || fixture_table_names).each do |table_name|
|
872
|
+
table_name = table_name.to_s.tr('.', '_')
|
879
873
|
|
880
|
-
|
881
|
-
|
874
|
+
define_method(table_name) do |*fixtures|
|
875
|
+
force_reload = fixtures.pop if fixtures.last == true || fixtures.last == :reload
|
882
876
|
|
883
|
-
|
877
|
+
@fixture_cache[table_name] ||= {}
|
884
878
|
|
885
|
-
|
886
|
-
|
879
|
+
instances = fixtures.map do |fixture|
|
880
|
+
@fixture_cache[table_name].delete(fixture) if force_reload
|
887
881
|
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
end
|
882
|
+
if @loaded_fixtures[table_name][fixture.to_s]
|
883
|
+
@fixture_cache[table_name][fixture] ||= @loaded_fixtures[table_name][fixture.to_s].find
|
884
|
+
else
|
885
|
+
raise StandardError, "No fixture with name '#{fixture}' found for table '#{table_name}'"
|
893
886
|
end
|
894
|
-
|
895
|
-
instances.size == 1 ? instances.first : instances
|
896
887
|
end
|
897
|
-
end
|
898
|
-
end
|
899
888
|
|
900
|
-
|
901
|
-
|
902
|
-
@uses_transaction.concat methods.map(&:to_s)
|
889
|
+
instances.size == 1 ? instances.first : instances
|
890
|
+
end
|
903
891
|
end
|
892
|
+
end
|
904
893
|
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
end
|
894
|
+
def uses_transaction(*methods)
|
895
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
896
|
+
@uses_transaction.concat methods.map(&:to_s)
|
909
897
|
end
|
910
898
|
|
911
|
-
def
|
912
|
-
|
913
|
-
|
899
|
+
def uses_transaction?(method)
|
900
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
901
|
+
@uses_transaction.include?(method.to_s)
|
914
902
|
end
|
903
|
+
end
|
915
904
|
|
916
|
-
|
917
|
-
|
905
|
+
def run_in_transaction?
|
906
|
+
use_transactional_fixtures &&
|
907
|
+
!self.class.uses_transaction?(method_name)
|
908
|
+
end
|
918
909
|
|
919
|
-
|
920
|
-
|
921
|
-
end
|
910
|
+
def setup_fixtures
|
911
|
+
return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
|
922
912
|
|
923
|
-
|
913
|
+
if pre_loaded_fixtures && !use_transactional_fixtures
|
914
|
+
raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
|
915
|
+
end
|
924
916
|
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
end
|
933
|
-
ActiveRecord::Base.connection.increment_open_transactions
|
934
|
-
ActiveRecord::Base.connection.begin_db_transaction
|
935
|
-
# Load fixtures for every test.
|
917
|
+
@fixture_cache = {}
|
918
|
+
@@already_loaded_fixtures ||= {}
|
919
|
+
|
920
|
+
# Load fixtures once and begin transaction.
|
921
|
+
if run_in_transaction?
|
922
|
+
if @@already_loaded_fixtures[self.class]
|
923
|
+
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
936
924
|
else
|
937
|
-
Fixtures.reset_cache
|
938
|
-
@@already_loaded_fixtures[self.class] = nil
|
939
925
|
load_fixtures
|
926
|
+
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
940
927
|
end
|
941
|
-
|
942
|
-
|
943
|
-
|
928
|
+
ActiveRecord::Base.connection.increment_open_transactions
|
929
|
+
ActiveRecord::Base.connection.transaction_joinable = false
|
930
|
+
ActiveRecord::Base.connection.begin_db_transaction
|
931
|
+
# Load fixtures for every test.
|
932
|
+
else
|
933
|
+
Fixtures.reset_cache
|
934
|
+
@@already_loaded_fixtures[self.class] = nil
|
935
|
+
load_fixtures
|
944
936
|
end
|
945
937
|
|
946
|
-
|
947
|
-
|
938
|
+
# Instantiate fixtures for every test if requested.
|
939
|
+
instantiate_fixtures if use_instantiated_fixtures
|
940
|
+
end
|
948
941
|
|
949
|
-
|
950
|
-
|
951
|
-
end
|
942
|
+
def teardown_fixtures
|
943
|
+
return unless defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
|
952
944
|
|
953
|
-
|
954
|
-
|
955
|
-
ActiveRecord::Base.connection.rollback_db_transaction
|
956
|
-
ActiveRecord::Base.connection.decrement_open_transactions
|
957
|
-
end
|
958
|
-
ActiveRecord::Base.clear_active_connections!
|
945
|
+
unless run_in_transaction?
|
946
|
+
Fixtures.reset_cache
|
959
947
|
end
|
960
948
|
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
949
|
+
# Rollback changes if a transaction is active.
|
950
|
+
if run_in_transaction? && ActiveRecord::Base.connection.open_transactions != 0
|
951
|
+
ActiveRecord::Base.connection.rollback_db_transaction
|
952
|
+
ActiveRecord::Base.connection.decrement_open_transactions
|
953
|
+
end
|
954
|
+
ActiveRecord::Base.clear_active_connections!
|
955
|
+
end
|
956
|
+
|
957
|
+
private
|
958
|
+
def load_fixtures
|
959
|
+
@loaded_fixtures = {}
|
960
|
+
fixtures = Fixtures.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
|
961
|
+
unless fixtures.nil?
|
962
|
+
if fixtures.instance_of?(Fixtures)
|
963
|
+
@loaded_fixtures[fixtures.name] = fixtures
|
964
|
+
else
|
965
|
+
fixtures.each { |f| @loaded_fixtures[f.name] = f }
|
971
966
|
end
|
972
967
|
end
|
968
|
+
end
|
973
969
|
|
974
|
-
|
975
|
-
|
970
|
+
# for pre_loaded_fixtures, only require the classes once. huge speed improvement
|
971
|
+
@@required_fixture_classes = false
|
976
972
|
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
end
|
973
|
+
def instantiate_fixtures
|
974
|
+
if pre_loaded_fixtures
|
975
|
+
raise RuntimeError, 'Load fixtures before instantiating them.' if Fixtures.all_loaded_fixtures.empty?
|
976
|
+
unless @@required_fixture_classes
|
977
|
+
self.class.require_fixture_classes Fixtures.all_loaded_fixtures.keys
|
978
|
+
@@required_fixture_classes = true
|
979
|
+
end
|
980
|
+
Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
|
981
|
+
else
|
982
|
+
raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
|
983
|
+
@loaded_fixtures.each do |table_name, fixtures|
|
984
|
+
Fixtures.instantiate_fixtures(self, table_name, fixtures, load_instances?)
|
990
985
|
end
|
991
986
|
end
|
987
|
+
end
|
992
988
|
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
end
|
989
|
+
def load_instances?
|
990
|
+
use_instantiated_fixtures != :no_instances
|
991
|
+
end
|
997
992
|
end
|
998
993
|
end
|