Skip to content

Rails Fixtures load order

December 17, 2010

This was a head breaking experience for me recently.

We all know that the fixtures files in rails load by default in alphabetical order. And the records inside every single file again load in alphabetical order (not from top to bottom as you define in the fixture file). Considering that having database level constraints (foreign keys, primary keys etc) is advisable idea in spite of having the rails model level relations (belongs_to, has_many etc), loading fixtures in alphabetical order is the most stupid thing I can ever think of. Imagine you have Account and Employee models and employee has_many accounts. So you have an employee_id sitting as a foreign key in the accounts table. Now you want to load your fixtures (rake db:fixtures:load), for test purpose say, which was my requirement. Since ‘A’ comes before ‘E’ in alphabetical order, rails tries to load the addresses first and then the employees fixture file. Obviously this fails because of foreign key violations. Database raising errors is perfectly making sense here. So I looked around for something  which may solve this problem and found that there are solutions available given by some people. But what surprised me is that there is nothing that rails core provided for this.

Anyways, so for people who are into this kinda problem, here is the best one called ActiveFixture that I came across and wish that it would get included in the rails core someday.

Again there is something that may surprise you again. Its not that rails has been stupid all these days to leave us in such a situation. It might so happen that you may not do anything for ordering of the fixtures and still would not get any error although you have foreign key relationships in the database. The reason actually lies in the active record’s database (postgres, mysql sql-lite etc) adapters class. Here is how it goes. While loading the fixtures (I am giving postgres example, as I am using postgres for this project and found it there), rails calls the following method in ActiveRecord::ConnectionAdapters::PostgreSQLAdapter:

def supports_disable_referential_integrity?() #:nodoc:
version = query("SHOW server_version")[0][0].split('.')
(version[0].to_i >= 8 && version[1].to_i >= 1) ? true : false
return false

So this method says, that if you pgsql version is x.y.z, then if  x >= 8 and y >= 1, then it will be able to defer the referential integrity for you and you could load the data from fixtures into your database easily without taking care of the ordering and without facing any data integrity errors 😀 Unfortunately I, in my team, was using 9.y.z version of pgsql and all my collegues were on 8.1.4. So they were not getting any errors and I was frustated to know WHY.

Well the secret lies in the ConnectionAdapters for rails 😀 I don’t know if we should take it as an advantage, that rails is trying to do or not, but until we have something more intelligent to infer the order of loading the fixtures files from the relationships in the models, rather than defining the load order manually as mentioned here, I am happy that its saving me some time.

2 Comments leave one →
  1. Marcin Mańk permalink
    April 5, 2011 10:17 am

    It`s a plain bug.
    Put this in an initializer (i.e. config/initializers/new_rais_defaults.tb):

    class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
    def supports_disable_referential_integrity?() #:nodoc:
    major, minor = query(“SHOW server_version”)[0][0].split(‘.’).map(&:to_i)
    (major >= 9 || major == 8 && minor >= 1) ? true : false
    rescue Exception=>e
    return false

  2. Mason permalink
    November 5, 2011 8:46 pm

    Note for anyone else who finds this post looking for a solution to this issue: If you declare you foreign key constraints as “DEFERRABLE INITIALLY DEFERRED” (for PostgreSQL) and you use transactional fixtures, then your constraint-related fixture load order issues should go away.

    For more info see:

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: