Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/trunk/activerecord/lib/active_record/fixtures.rb

Revision 9191, 33.5 kB (checked in by bitsweat, 3 months ago)

Ruby 1.9 compat: delete DEFAULTS key from Hash not Omap array

  • Property svn:executable set to *
Line 
1 require 'erb'
2 require 'yaml'
3 require 'csv'
4 require 'active_support/test_case'
5
6 if RUBY_VERSION < '1.9'
7   module YAML #:nodoc:
8     class Omap #:nodoc:
9       def keys;   map { |k, v| k } end
10       def values; map { |k, v| v } end
11     end
12   end
13 end
14
15 if defined? ActiveRecord
16   class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
17   end
18 else
19   class FixtureClassNotFound < StandardError #:nodoc:
20   end
21 end
22
23 # Fixtures are a way of organizing data that you want to test against; in short, sample data. They come in 3 flavors:
24 #
25 #   1.  YAML fixtures
26 #   2.  CSV fixtures
27 #   3.  Single-file fixtures
28 #
29 # = YAML fixtures
30 #
31 # This type of fixture is in YAML format and the preferred default. YAML is a file format which describes data structures
32 # in a non-verbose, human-readable format. It ships with Ruby 1.8.1+.
33 #
34 # Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed
35 # by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
36 # put your files in <your-rails-app>/test/fixtures/). The fixture file ends with the .yml file extension (Rails example:
37 # "<your-rails-app>/test/fixtures/web_sites.yml"). The format of a YAML fixture file looks like this:
38 #
39 #   rubyonrails:
40 #     id: 1
41 #     name: Ruby on Rails
42 #     url: http://www.rubyonrails.org
43 #
44 #   google:
45 #     id: 2
46 #     name: Google
47 #     url: http://www.google.com
48 #
49 # This YAML fixture file includes two fixtures.  Each YAML fixture (ie. record) is given a name and is followed by an
50 # indented list of key/value pairs in the "key: value" format.  Records are separated by a blank line for your viewing
51 # pleasure.
52 #
53 # Note that YAML fixtures are unordered. If you want ordered fixtures, use the omap YAML type.  See http://yaml.org/type/omap.html
54 # for the specification.  You will need ordered fixtures when you have foreign key constraints on keys in the same table.
55 # This is commonly needed for tree structures.  Example:
56 #
57 #    --- !omap
58 #    - parent:
59 #        id:         1
60 #        parent_id:  NULL
61 #        title:      Parent
62 #    - child:
63 #        id:         2
64 #        parent_id:  1
65 #        title:      Child
66 #
67 # = CSV fixtures
68 #
69 # Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored
70 # in a single file, but instead end with the .csv file extension (Rails example: "<your-rails-app>/test/fixtures/web_sites.csv")
71 #
72 # The format of this type of fixture file is much more compact than the others, but also a little harder to read by us
73 # humans.  The first line of the CSV file is a comma-separated list of field names.  The rest of the file is then comprised
74 # of the actual data (1 per line).  Here's an example:
75 #
76 #   id, name, url
77 #   1, Ruby On Rails, http://www.rubyonrails.org
78 #   2, Google, http://www.google.com
79 #
80 # Should you have a piece of data with a comma character in it, you can place double quotes around that value.  If you
81 # need to use a double quote character, you must escape it with another double quote.
82 #
83 # Another unique attribute of the CSV fixture is that it has *no* fixture name like the other two formats.  Instead, the
84 # fixture names are automatically generated by deriving the class name of the fixture file and adding an incrementing
85 # number to the end.  In our example, the 1st fixture would be called "web_site_1" and the 2nd one would be called
86 # "web_site_2".
87 #
88 # Most databases and spreadsheets support exporting to CSV format, so this is a great format for you to choose if you
89 # have existing data somewhere already.
90 #
91 # = Single-file fixtures
92 #
93 # This type of fixture was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats.
94 # Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory
95 # appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
96 # put your files in <your-rails-app>/test/fixtures/<your-model-name>/ -- like <your-rails-app>/test/fixtures/web_sites/ for the WebSite
97 # model).
98 #
99 # Each text file placed in this directory represents a "record".  Usually these types of fixtures are named without
100 # extensions, but if you are on a Windows machine, you might consider adding .txt as the extension.  Here's what the
101 # above example might look like:
102 #
103 #   web_sites/google
104 #   web_sites/yahoo.txt
105 #   web_sites/ruby-on-rails
106 #
107 # The file format of a standard fixture is simple.  Each line is a property (or column in db speak) and has the syntax
108 # of "name => value".  Here's an example of the ruby-on-rails fixture above:
109 #
110 #   id => 1
111 #   name => Ruby on Rails
112 #   url => http://www.rubyonrails.org
113 #
114 # = Using Fixtures
115 #
116 # Since fixtures are a testing construct, we use them in our unit and functional tests.  There are two ways to use the
117 # fixtures, but first let's take a look at a sample unit test:
118 #
119 #   require 'web_site'
120 #
121 #   class WebSiteTest < ActiveSupport::TestCase
122 #     def test_web_site_count
123 #       assert_equal 2, WebSite.count
124 #     end
125 #   end
126 #
127 # As it stands, unless we pre-load the web_site table in our database with two records, this test will fail.  Here's the
128 # easiest way to add fixtures to the database:
129 #
130 #   ...
131 #   class WebSiteTest < ActiveSupport::TestCase
132 #     fixtures :web_sites # add more by separating the symbols with commas
133 #   ...
134 #
135 # By adding a "fixtures" method to the test case and passing it a list of symbols (only one is shown here though), we trigger
136 # the testing environment to automatically load the appropriate fixtures into the database before each test.
137 # To ensure consistent data, the environment deletes the fixtures before running the load.
138 #
139 # In addition to being available in the database, the fixtures are also loaded into a hash stored in an instance variable
140 # of the test case.  It is named after the symbol... so, in our example, there would be a hash available called
141 # @web_sites.  This is where the "fixture name" comes into play.
142 #
143 # On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name.
144 # So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics:
145 #
146 #   # test if the object created from the fixture data has the same attributes as the data itself
147 #   def test_find
148 #     assert_equal @web_sites["rubyonrails"]["name"], @rubyonrails.name
149 #   end
150 #
151 # As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return
152 # "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded
153 # from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual
154 # fixtures available as instance variables @web_site_1 and @web_site_2.
155 #
156 # If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options.
157 #
158 #   - to completely disable instantiated fixtures:
159 #       self.use_instantiated_fixtures = false
160 #
161 #   - to keep the fixture instance (@web_sites) available, but do not automatically 'find' each instance:
162 #       self.use_instantiated_fixtures = :no_instances
163 #
164 # Even if auto-instantiated fixtures are disabled, you can still access them
165 # by name via special dynamic methods. Each method has the same name as the
166 # model, and accepts the name of the fixture to instantiate:
167 #
168 #   fixtures :web_sites
169 #
170 #   def test_find
171 #     assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
172 #   end
173 #
174 # = Dynamic fixtures with ERb
175 #
176 # Some times you don't care about the content of the fixtures as much as you care about the volume. In these cases, you can
177 # mix ERb in with your YAML or CSV fixtures to create a bunch of fixtures for load testing, like:
178 #
179 #   <% for i in 1..1000 %>
180 #   fix_<%= i %>:
181 #     id: <%= i %>
182 #     name: guy_<%= 1 %>
183 #   <% end %>
184 #
185 # This will create 1000 very simple YAML fixtures.
186 #
187 # Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>.
188 # This is however a feature to be used with some caution. The point of fixtures are that they're stable units of predictable
189 # sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application
190 # is properly testable. Hence, dynamic values in fixtures are to be considered a code smell.
191 #
192 # = Transactional fixtures
193 #
194 # TestCases can use begin+rollback to isolate their changes to the database instead of having to delete+insert for every test case.
195 # They can also turn off auto-instantiation of fixture data since the feature is costly and often unused.
196 #
197 #   class FooTest < ActiveSupport::TestCase
198 #     self.use_transactional_fixtures = true
199 #     self.use_instantiated_fixtures = false
200 #   
201 #     fixtures :foos
202 #   
203 #     def test_godzilla
204 #       assert !Foo.find(:all).empty?
205 #       Foo.destroy_all
206 #       assert Foo.find(:all).empty?
207 #     end
208 #   
209 #     def test_godzilla_aftermath
210 #       assert !Foo.find(:all).empty?
211 #     end
212 #   end
213 #   
214 # If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures,
215 # then you may omit all fixtures declarations in your test cases since all the data's already there and every case rolls back its changes.
216 #
217 # In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to true. This will provide
218 # access to fixture data for every table that has been loaded through fixtures (depending on the value of +use_instantiated_fixtures+)
219 #
220 # When *not* to use transactional fixtures:
221 #   1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit,
222 #      particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify
223 #      the results of your transaction until Active Record supports nested transactions or savepoints (in progress).
224 #   2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
225 #      Use InnoDB, MaxDB, or NDB instead.
226 #
227 # = Advanced YAML Fixtures
228 #
229 # YAML fixtures that don't specify an ID get some extra features:
230 #
231 # * Stable, autogenerated ID's
232 # * Label references for associations (belongs_to, has_one, has_many)
233 # * HABTM associations as inline lists
234 # * Autofilled timestamp columns
235 # * Fixture label interpolation
236 # * Support for YAML defaults
237 #
238 # == Stable, autogenerated ID's
239 #
240 # Here, have a monkey fixture:
241 #
242 #   george:
243 #     id: 1
244 #     name: George the Monkey
245 #
246 #   reginald:
247 #     id: 2
248 #     name: Reginald the Pirate
249 #
250 # Each of these fixtures has two unique identifiers: one for the database
251 # and one for the humans. Why don't we generate the primary key instead?
252 # Hashing each fixture's label yields a consistent ID:
253 #
254 #   george: # generated id: 503576764
255 #     name: George the Monkey
256 #
257 #   reginald: # generated id: 324201669
258 #     name: Reginald the Pirate
259 #
260 # ActiveRecord looks at the fixture's model class, discovers the correct
261 # primary key, and generates it right before inserting the fixture
262 # into the database.
263 #
264 # The generated ID for a given label is constant, so we can discover
265 # any fixture's ID without loading anything, as long as we know the label.
266 #
267 # == Label references for associations (belongs_to, has_one, has_many)
268 #
269 # Specifying foreign keys in fixtures can be very fragile, not to
270 # mention difficult to read. Since ActiveRecord can figure out the ID of
271 # any fixture from its label, you can specify FK's by label instead of ID.
272 #
273 # === belongs_to
274 #
275 # Let's break out some more monkeys and pirates.
276 #
277 #   ### in pirates.yml
278 #
279 #   reginald:
280 #     id: 1
281 #     name: Reginald the Pirate
282 #     monkey_id: 1
283 #
284 #   ### in monkeys.yml
285 #
286 #   george:
287 #     id: 1
288 #     name: George the Monkey
289 #     pirate_id: 1
290 #
291 # Add a few more monkeys and pirates and break this into multiple files,
292 # and it gets pretty hard to keep track of what's going on. Let's
293 # use labels instead of ID's:
294 #
295 #   ### in pirates.yml
296 #
297 #   reginald:
298 #     name: Reginald the Pirate
299 #     monkey: george
300 #
301 #   ### in monkeys.yml
302 #
303 #   george:
304 #     name: George the Monkey
305 #     pirate: reginald
306 #
307 # Pow! All is made clear. ActiveRecord reflects on the fixture's model class,
308 # finds all the +belongs_to+ associations, and allows you to specify
309 # a target *label* for the *association* (monkey: george) rather than
310 # a target *id* for the *FK* (monkey_id: 1).
311 #
312 # ==== Polymorphic belongs_to
313 #
314 # Supporting polymorphic relationships is a little bit more complicated, since
315 # ActiveRecord needs to know what type your association is pointing at. Something
316 # like this should look familiar:
317 #
318 #   ### in fruit.rb
319 #
320 #   belongs_to :eater, :polymorphic => true
321 #
322 #   ### in fruits.yml
323 #
324 #   apple:
325 #     id: 1
326 #     name: apple
327 #     eater_id: 1
328 #     eater_type: Monkey
329 #
330 # Can we do better? You bet!
331 #
332 #   apple:
333 #     eater: george (Monkey)
334 #
335 # Just provide the polymorphic target type and ActiveRecord will take care of the rest.
336 #
337 # === has_and_belongs_to_many
338 #
339 # Time to give our monkey some fruit.
340 #
341 #   ### in monkeys.yml
342 #
343 #   george:
344 #     id: 1
345 #     name: George the Monkey
346 #     pirate_id: 1
347 #
348 #   ### in fruits.yml
349 #
350 #   apple:
351 #     id: 1
352 #     name: apple
353 #
354 #   orange:
355 #     id: 2
356 #     name: orange
357 #
358 #   grape:
359 #     id: 3
360 #     name: grape
361 #
362 #   ### in fruits_monkeys.yml
363 #
364 #   apple_george:
365 #     fruit_id: 1
366 #     monkey_id: 1
367 #
368 #   orange_george:
369 #     fruit_id: 2
370 #     monkey_id: 1
371 #
372 #   grape_george:
373 #     fruit_id: 3
374 #     monkey_id: 1
375 #
376 # Let's make the HABTM fixture go away.
377 #
378 #   ### in monkeys.yml
379 #
380 #   george:
381 #     name: George the Monkey
382 #     pirate: reginald
383 #     fruits: apple, orange, grape
384 #
385 #   ### in fruits.yml
386 #
387 #   apple:
388 #     name: apple
389 #
390 #   orange:
391 #     name: orange
392 #
393 #   grape:
394 #     name: grape
395 #
396 # Zap! No more fruits_monkeys.yml file. We've specified the list of fruits
397 # on George's fixture, but we could've just as easily specified a list
398 # of monkeys on each fruit. As with +belongs_to+, ActiveRecord reflects on
399 # the fixture's model class and discovers the +has_and_belongs_to_many+
400 # associations.
401 #
402 # == Autofilled timestamp columns
403 #
404 # If your table/model specifies any of ActiveRecord's
405 # standard timestamp columns (created_at, created_on, updated_at, updated_on),
406 # they will automatically be set to Time.now.
407 #
408 # If you've set specific values, they'll be left alone.
409 #
410 # == Fixture label interpolation
411 #
412 # The label of the current fixture is always available as a column value:
413 #
414 #   geeksomnia:
415 #     name: Geeksomnia's Account
416 #     subdomain: $LABEL
417 #
418 # Also, sometimes (like when porting older join table fixtures) you'll need
419 # to be able to get ahold of the identifier for a given label. ERB
420 # to the rescue:
421 #
422 #   george_reginald:
423 #     monkey_id: <%= Fixtures.identify(:reginald) %>
424 #     pirate_id: <%= Fixtures.identify(:george) %>
425 #
426 # == Support for YAML defaults
427 #
428 # You probably already know how to use YAML to set and reuse defaults in
429 # your +database.yml+ file,. You can use the same technique in your fixtures:
430 #
431 #   DEFAULTS: &DEFAULTS
432 #     created_on: <%= 3.weeks.ago.to_s(:db) %>
433 #
434 #   first:
435 #     name: Smurf
436 #     <<: *DEFAULTS
437 #
438 #   second:
439 #     name: Fraggle
440 #     <<: *DEFAULTS
441 #
442 # Any fixture labeled "DEFAULTS" is safely ignored.
443
444 class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
445   DEFAULT_FILTER_RE = /\.ya?ml$/
446
447   @@all_cached_fixtures = {}
448
449   def self.reset_cache(connection = nil)
450     connection ||= ActiveRecord::Base.connection
451     @@all_cached_fixtures[connection.object_id] = {}
452   end
453
454   def self.cache_for_connection(connection)
455     @@all_cached_fixtures[connection.object_id] ||= {}
456     @@all_cached_fixtures[connection.object_id]
457   end
458
459   def self.fixture_is_cached?(connection, table_name)
460     cache_for_connection(connection)[table_name]
461   end
462
463   def self.cached_fixtures(connection, keys_to_fetch = nil)
464     if keys_to_fetch
465       fixtures = cache_for_connection(connection).values_at(*keys_to_fetch)
466     else
467       fixtures = cache_for_connection(connection).values
468     end
469     fixtures.size > 1 ? fixtures : fixtures.first
470   end
471
472   def self.cache_fixtures(connection, fixtures)
473     cache_for_connection(connection).update(fixtures.index_by { |f| f.table_name })
474   end
475
476   def self.instantiate_fixtures(object, table_name, fixtures, load_instances = true)
477     object.instance_variable_set "@#{table_name.to_s.gsub('.','_')}", fixtures
478     if load_instances
479       ActiveRecord::Base.silence do
480         fixtures.each do |name, fixture|
481           begin
482             object.instance_variable_set "@#{name}", fixture.find
483           rescue FixtureClassNotFound
484             nil
485           end
486         end
487       end
488     end
489   end
490
491   def self.instantiate_all_loaded_fixtures(object, load_instances = true)
492     all_loaded_fixtures.each do |table_name, fixtures|
493       Fixtures.instantiate_fixtures(object, table_name, fixtures, load_instances)
494     end
495   end
496
497   cattr_accessor :all_loaded_fixtures
498   self.all_loaded_fixtures = {}
499
500   def self.create_fixtures(fixtures_directory, table_names, class_names = {})
501     table_names = [table_names].flatten.map { |n| n.to_s }
502     connection  = block_given? ? yield : ActiveRecord::Base.connection
503
504     table_names_to_fetch = table_names.reject { |table_name| fixture_is_cached?(connection, table_name) }
505
506     unless table_names_to_fetch.empty?
507       ActiveRecord::Base.silence do
508         connection.disable_referential_integrity do
509           fixtures_map = {}
510
511           fixtures = table_names_to_fetch.map do |table_name|
512             fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s))
513           end
514
515           all_loaded_fixtures.update(fixtures_map)
516
517           connection.transaction(Thread.current['open_transactions'].to_i == 0) do
518             fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
519             fixtures.each { |fixture| fixture.insert_fixtures }
520
521             # Cap primary key sequences to max(pk).
522             if connection.respond_to?(:reset_pk_sequence!)
523               table_names.each do |table_name|
524                 connection.reset_pk_sequence!(table_name)
525               end
526             end
527           end
528
529           cache_fixtures(connection, fixtures)
530         end
531       end
532     end
533     cached_fixtures(connection, table_names)
534   end
535
536   # Returns a consistent identifier for +label+. This will always
537   # be a positive integer, and will always be the same for a given
538   # label, assuming the same OS, platform, and version of Ruby.
539   def self.identify(label)
540     label.to_s.hash.abs
541   end
542
543   attr_reader :table_name
544
545   def initialize(connection, table_name, class_name, fixture_path, file_filter = DEFAULT_FILTER_RE)
546     @connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter
547     @class_name = class_name ||
548                   (ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize)
549     @table_name = ActiveRecord::Base.table_name_prefix + @table_name + ActiveRecord::Base.table_name_suffix
550     @table_name = class_name.table_name if class_name.respond_to?(:table_name)
551     @connection = class_name.connection if class_name.respond_to?(:connection)
552     read_fixture_files
553   end
554
555   def delete_existing_fixtures
556     @connection.delete "DELETE FROM #{@connection.quote_table_name(table_name)}", 'Fixture Delete'
557   end
558
559   def insert_fixtures
560     now = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
561     now = now.to_s(:db)
562
563     # allow a standard key to be used for doing defaults in YAML
564     if is_a?(Hash)
565       delete('DEFAULTS')
566     else
567       delete(assoc('DEFAULTS'))
568     end
569
570     # track any join tables we need to insert later
571     habtm_fixtures = Hash.new do |h, habtm|
572       h[habtm] = HabtmFixtures.new(@connection, habtm.options[:join_table], nil, nil)
573     end
574
575     each do |label, fixture|
576       row = fixture.to_hash
577
578       if model_class && model_class < ActiveRecord::Base
579         # fill in timestamp columns if they aren't specified and the model is set to record_timestamps
580         if model_class.record_timestamps
581           timestamp_column_names.each do |name|
582             row[name] = now unless row.key?(name)
583           end
584         end
585
586         # interpolate the fixture label
587         row.each do |key, value|
588           row[key] = label if value == "$LABEL"
589         end
590
591         # generate a primary key if necessary
592         if has_primary_key_column? && !row.include?(primary_key_name)
593           row[primary_key_name] = Fixtures.identify(label)
594         end
595
596         # If STI is used, find the correct subclass for association reflection
597         reflection_class =
598           if row.include?(inheritance_column_name)
599             row[inheritance_column_name].constantize rescue model_class
600           else
601             model_class
602           end
603
604         reflection_class.reflect_on_all_associations.each do |association|
605           case association.macro
606           when :belongs_to
607             # Do not replace association name with association foreign key if they are named the same
608             fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
609
610             if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
611               if association.options[:polymorphic]
612                 if value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
613                   target_type = $1
614                   target_type_name = (association.options[:foreign_type] || "#{association.name}_type").to_s
615
616                   # support polymorphic belongs_to as "label (Type)"
617                   row[target_type_name] = target_type
618                 end
619               end
620
621               row[fk_name] = Fixtures.identify(value)
622             end
623           when :has_and_belongs_to_many
624             if (targets = row.delete(association.name.to_s))
625               targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
626               join_fixtures = habtm_fixtures[association]
627
628               targets.each do |target|
629                 join_fixtures["#{label}_#{target}"] = Fixture.new(
630                   { association.primary_key_name => row[primary_key_name],
631                     association.association_foreign_key => Fixtures.identify(target) }, nil)
632               end
633             end
634           end
635         end
636       end
637
638       @connection.insert_fixture(fixture, @table_name)
639     end
640
641     # insert any HABTM join tables we discovered
642     habtm_fixtures.values.each do |fixture|
643       fixture.delete_existing_fixtures
644       fixture.insert_fixtures
645     end
646   end
647
648   private
649     class HabtmFixtures < ::Fixtures #:nodoc:
650       def read_fixture_files; end
651     end
652
653     def model_class
654       unless defined?(@model_class)
655         @model_class =
656           if @class_name.nil? || @class_name.is_a?(Class)
657             @class_name
658           else
659             @class_name.constantize rescue nil
660           end
661       end
662
663       @model_class
664     end
665
666     def primary_key_name
667       @primary_key_name ||= model_class && model_class.primary_key
668     end
669
670     def has_primary_key_column?
671       @has_primary_key_column ||= model_class && primary_key_name &&
672         model_class.columns.find { |c| c.name == primary_key_name }
673     end
674
675     def timestamp_column_names
676       @timestamp_column_names ||= %w(created_at created_on updated_at updated_on).select do |name|
677         column_names.include?(name)
678       end
679     end
680
681     def inheritance_column_name
682       @inheritance_column_name ||= model_class && model_class.inheritance_column
683     end
684
685     def column_names
686       @column_names ||= @connection.columns(@table_name).collect(&:name)
687     end
688
689     def read_fixture_files
690       if File.file?(yaml_file_path)
691         read_yaml_fixture_files
692       elsif File.file?(csv_file_path)
693         read_csv_fixture_files
694       end