Put your message here! Contact me for more information
 
 








 

RailsI’ve just released ActiveFixture, an enhancement to the Rails db:fixtures:load rake task. Currently db:fixtures:load doesn’t take into account the foreign key constraints hence with any tables that have foreign keys defined, db:fixtures:load would just fail miserably. As Rails is increasingly getting more into the enterprise world, the ability to handle foreign key correctly becomes more important.

I flew to New York last weekend for the VSLive! Conference. While attending VSLive! talks during the day, my mind was mostly occupied with how to solve this foreign key issue at night. After 2 days and trying multiple ways and still unable to solve the problem, I suddenly remembered about graph (good old CS classes). I turned the problem of determining the order of loading fixtures files into a graph problem of how to traverse the graph in a certain order. Breadth-first-search doesn’t give the correct answer, Depth-first-search seems to have some potentials. When I tried Depth-first-search Post order traversal, suddenly I realized that DFS post order gives the perfect solution. What’s even more beautiful is the entire traversal algorithm was only a couple lines of Ruby code as you can see from the source.

I’ve learned quite a bit about Rails and Ruby while writing ActiveFixture. I poked around the core ActiveRecord classes and see how fixture is being handled, I then learned how to use reflection to get meta data from the ActiveRecord models, then how to write rake task and componentize everything into a plugin. In the end, I feel I like working with Ruby and Rails even more. .NET is cool but somehow, to me, Ruby is more fun to work with, except for the fact that there’s no GUI debugger. I would say I would have been able to write ActiveFixture in much less amount of time had I had a Rails/Ruby IDE with an interactive debugger.

The next time I write something for Rails, I would probably give Ruby in Steel a shot. It’s quite frustrated when you are exploring Ruby, especially when someone like me isn’t that familiar with Ruby. I love the Watch and Intermediate Window in Visual Studio simply because I can hit a breakpoint and examine the application and all the variables at that moment. Currently we don’t have anything similar for Ruby and Rails for free. Ruby in Steel seems to have potentials, but $199 is quite a barrier to entry to any ruby-rails-fan. In fact, one of the main question that my boss at work asked me about Ruby on Rails, is if Ruby has any good IDE. My company is a Microsoft shop so we use Visual Studio extensively. It’s hard to convince someone who code in Visual Studio for a living to switch to a notepad-like editor (”no Intellisense, no thanks”) and start learning Ruby on Rails. Personally I use (and pay for) e-editor, however, I do miss the intellisense and the ability to hit F5 anytime to kill that freaking bug…Okay, enough of my ranting.

Anyway, here’s the good news in short: ActiveFixture is released and ready for abused. Current version is under-tested (I haven’t written any unit tests yet) and may contain bugs. For Wars of Earth, I have about 20 tables with a whole bunch of foreign key constraints (with circular references too) so I’m quite confident that ActiveFixture will work for you.

Download:

  • SVN: http://activefixture.rubyforge.org/svn/

Install:

  • Copy into the RAILS_ROOT/vendors/plugins
  • As always, RTFM. See README for more information. I wrote a little explanation on how ActiveFixture works so enjoy :) It’s a nice and elegant algorithm to solve a tricky problem.

Usage:

  • Make sure you have all the required yml/yaml/csv files
  • Defined all belongs_to relationships inside your models
  • Run
rake db:fixtures:activeload

And Support:
Please vote for ActiveFixture to get included in Rails core. I’ll have even more incentives to write even more useful Rails plugins.

keywords spam: db:fixtures:load, db:fixtures:activeload, rails foreign key constraints fixtures, fixtures loading order


Tags: , ,

 

18 Responses to “ActiveFixture: correct fixture loading with foreign key constraints



9:42 am
September 25, 2007
#60015

Alex,

First off, thanks for creating such a useful plugin/rake task. You are solving the exact problem I have.

Now the bad news. The ActiveFixture plugin doesn’t appear to work with polymorphic associations (http://www.railsapi.org/belongs_to). I use polymorphic associations in cases where I want to associate one model to any other model.

Specifically, line 25 of activefixture.rb fails when trying to create a constant from the class name specified in the “belongs_to” association.
In the case of a polymorphic association, the class name doesn’t actually map to a real ActiveRecord model class.

You can see this for yourself by creating a sample Rails app and installing the following plugin:

http://www.juixe.com/techknow/index.php/2006/06/18/acts-as-commentable-plugin/

Denis




12:56 pm
September 25, 2007
#60054

@Denis,

Thanks for the note. I’ve fixed the plugin to properly skip over polymorphic association.

Alex




1:28 pm
September 25, 2007
#60057

Very cool, thanks for the quick turnaround!

One other thing - I would like to use ActiveFixture to load data from locations other than “#{RAILS_ROOT}/test/fixtures”. In my particular case I want to load data from “#{RAILS_ROOT}/db/reference (i.e. this is a robust set of data for the reference implementation of my app).

Any chance you would be willing to enhance the rake task and plugin to allow the path to the YAMLs to be passed in as a command line parameter?




11:39 am
September 28, 2007
#61219

Alex,

I found another problem with the plugin. It doesn’t handle self-referential relationhips, resulting in Rake aborting due to a “stack level too deep” error (infinite loop). I ran Rake with the –trace option, and the problem is in activefixture.rb in the _post_order_traverse method (line 117 and 118).

You should be able to easily create this problem by creating a table which has a foreign key field that points back at the table. In my particular case, I have a projects table which has a parent_id field. The value stored in the field points at the project’s parent project (i.e. projects can be nested).

In my Project model, I have the following:

class Project “Project”, :foreign_key => “parent_id”
has_many :projects, :class_name => “Project”, :foreign_key => “parent_id”
end

Denis




11:40 am
September 28, 2007
#61221

Looks like the code example in my previous post didn’t get pasted properly. Trying again…

class Project “Project”, :foreign_key => “parent_id”
has_many :projects, :class_name => “Project”, :foreign_key => “parent_id”
end

Hope it gets saved ok this time.

Denis




11:42 am
September 28, 2007
#61222

Nope, didn’t save this time either.

Basically, the Project class has a “belongs to” and “has many relationships which use the “parent id” foreign key to provide access to the project’s parent project and its subprojects.

Denis




BrianHartin
12:50 pm
September 28, 2007
#61233

Toplogical sort (they typical dependency-resolution algorithm from graph theory) is implemented in RGL, the Ruby graph library.

require ‘rgl/adjacency’
require ‘rgl/topsort’

directed_graph = RGL::DirectedAdjacencyGraph[]
# For each foreign key (t1 -> t2)
directed_graph.add_edge(t1, t2)
directed_graph.topsort_iterator.to_a # Returns an ordered array




12:02 am
September 29, 2007
#61377

@Denis,
I’ve fixed the bug. Thanks again for reporting the bugs.

@Brian Hartin,
I was looking into RGL at the time, however I decided that I didn’t want to force user to install more gem packages just to get ActiveFixture to work. Also it’s been a while since I did some “real programming” that requires a real algorithm so I took that as a challenge. Writing the graph traversal wasn’t that bad and I enjoyed it a lot.




Ra
2:59 am
October 2, 2007
#62059

10x very much Alex, you solved my problem.
I’m using you plugin with with Eclipse/Aptana/Rails, unfotunately you plug-in is not listed :-(. Installed by hand.

The tricky part was to define class and foreign key in has_many and belongs_to definition, as mentioned in readme.
In my case I had to define fixture’s file with the name of real tables (schema).




Nikos D.
9:33 am
January 30, 2008
#108603

Excellent - thanks a lot!

I will let you know if i find anything ‘unusual’ going on… :)




Romulo Velasquez
9:07 am
April 3, 2008
#137868

Gonna give this a try. Hopefully it solves my testing issues with foreign key constraints. Thanks for the work!




6:21 pm
May 4, 2008
#151068

If you need GUI debugger for Rails, Netbeans 6.1 is the way to go. It’s just like debugging .NET when using it.

Nice work anyway!




Diaz
10:05 am
May 15, 2008
#155650

sorry to ask if it is a very basic question, but how do i do to when i simply run rake or rake test it loads the fixtures using this plugin instead of the default action??

plz answer…




10:30 am
May 15, 2008
#155656

@Diaz

Once you have installed the plugin, you can then run

rake db:fixtures:activeload

instead of the usual

rake db:fixtures:load

Currently ActveLoad doesn’t support smart fixture loading during unit-testing yet. I’m not planning to work on it yet but probably will implement it when I need to do more extensive testings.




Diaz
2:57 am
May 16, 2008
#155894

ok, i just thought this could soulve the problem of when i run ‘rake test’ it fails all the tests because i added the foreign keys with the plugin ‘foreign_key_migrations’ from redhill. Do you have a tip or a idea to solve this?

thanks.




10:09 am
May 16, 2008
#156018

@Diaz,

To use ActiveLoad during testing, we will have to override how Rails handles the fixtures. I know it is possible to write a wrapper for the ActiveLoad method and define an “alias” to the original “load fixture” method. The wrapper would then determine the dependencies and load the models accordingly. With that said, I just haven’t got to do it yet. The tricky part is to figure how to overide and hookup ActiveLoad in place during testing.

Since you’re requesting, once I have cleared out my projects list a bit, I’ll look into implementing this feature.

Cheers!




Diaz
8:49 am
May 19, 2008
#157122

hey, thanks for what you doing. By the way, i’m having a litle issue here, in the Models folder i have a file that is not a class but a module that i load in almost all the others model files, so it is giving a error about the reflection that it offcourse can’t do, between the lines 14 to 31…

what should i change for it to run fine?




12:26 am
June 7, 2008
#165712

I received a large amount of spam just for this post so I decided to close out the comment feature. If you need to leave a comment, please let me know and I will re-enable the feature.

Alex