![]() |
Articles Feed |
Categories
Archives
- July 2010 (5)
- June 2010 (4)
- April 2010 (3)
- March 2010 (2)
- February 2010 (2)
- January 2010 (1)
- December 2009 (1)
- October 2009 (2)
- September 2009 (2)
- August 2009 (1)
- July 2009 (5)
- June 2009 (2)
- May 2009 (2)
- April 2009 (8)
- March 2009 (7)
- January 2009 (2)
- December 2008 (3)
- November 2008 (5)
- October 2008 (4)
- September 2008 (6)
- August 2008 (4)
- July 2008 (5)
- June 2008 (5)
- May 2008 (4)
- April 2008 (2)
- February 2008 (4)
- January 2008 (2)
- December 2007 (2)
- November 2007 (2)
- October 2007 (2)
- September 2007 (1)
- August 2007 (3)
- July 2007 (1)
- June 2007 (4)
- May 2007 (7)
- April 2007 (2)
- February 2007 (3)
- January 2007 (3)
- November 2006 (3)
- October 2006 (3)
- September 2006 (17)
- November 2004 (1)
Sharing a Database Among Multiple Rails Applications
by: jim | February 20th, 2007 |
A sign of the success of Ruby on Rails is the size of applications being written with it. Currently, we are working on a project with many interconnecting modules that we split up into separate Rails applications. However, the business domain was the same among the projects, resulting in the different projects sharing the same database. This article discusses the way we’ve accomplished this.
Create a Lib Project
We first need a place to pull our common classes into. This will not be a Rails application; it will just be a Ruby module that your Rails application will require. Our directory structure will look something like this:
/projects/my_lib --> lib --> spec
Now we can move on to the actual refactoring.
Pull the Models Out
The first step is the easiest: pull out the models from the app/models directory of your Rails application into the lib directory of your new library. In the config/environments.rb file within your Rails application, you will need to add this new directory to your Ruby search path by adding this line to the end of the file.
- $: << File.dirname(__FILE__) + '/your_lib_path'
More on the Ruby search path later.
Pull the Tests Out
Let’s move on to making our specs pass. Now that we don’t have the Ruby environments loaded up as part of our test helpers (spec_helper for the rspecers out there), we need to establish an Active Record connection ourselves. Create a spec helper for our lib specs and start it with the connection to the database like so.
- require 'rubygems'
- require 'active_record'
- ActiveRecord::Base.establish_connection(
- :adapter => "postgresql",
- :host => "localhost",
- :username => "rails",
- :password => "",
- :database => "<db name>_test"
- )
This is the same way Rails sets up your database connections for active record when you load the Rails environment. Now your specs just need to require this new spec_helper in order to get Active Record functioning.
Use Models Across Projects
Now you are free to use the same database across many projects. To do this, you just need to either require a single lib file that loads all the models, or you could put the lib directory in your Ruby search path.
Ruby Search Path vs. Lib Require File
The new common library will need to be included in your rails application. There are two methods we have used to do this. The first is to create a library file that does nothing more than requires all of the common lib files, looking something like the following.
- require File.expand_path(File.dirname(__FILE__) + '/my_lib/lib/file_a'
- require File.expand_path(File.dirname(__FILE__) + '/my_lib/lib/file_b'
- require File.expand_path(File.dirname(__FILE__) + '/my_lib/lib/file_c'
- require File.expand_path(File.dirname(__FILE__) + '/my_lib/lib/file_d'
- require File.expand_path(File.dirname(__FILE__) + '/my_lib/lib/file_e'
The problem with this approach is it requires you to sequence the require statements in the appropriate order, or else you will get errors about missing objects. The benefit is that you load the entire environment in one place rather than adding require statements at the top of each file to include the needed external dependencies. These code files that do nothing but require files are no stranger to Ruby; however, they must be managed properly as they become temperamental and irritable when dependencies are mixed up.
The other approach we have used is what I recommended above. In your Rails application’s environment, add the lib directory to your search path, and include the require statements as needed in each model file. Of course, by including one file you will be implicitly including all of the dependencies. Using this technique, you can eliminate files that just require other files.

October 18th, 2008 at 06:32 PM Have you considered using a gem to distribute these models across your applications?
October 18th, 2008 at 06:32 PM Yes. Gems were one of the first options considered. But gems would add extra weight that we don't need. We'd have to keep track of gem versions, bundling, distributing, etc. Right now our deployment technique is a simple SVN checkout. Gems would complicate this. Then there's the complication of development with gems. Having the gem installed on the same machine where the code is under development adds confusion. You'd always be asking yourself, "Am I sure it's the development code being executed or is it the gem?" At some point down the road we may encounter the need to gem up the libraries. For the time being, Jim's solution is sufficient.
October 18th, 2008 at 06:32 PM Nice trick. Really nice! I have followed your advice and it works and its simple. But I am stuck in sessions. I am having trouble sharing sessions between the rails app. Are you planning on doing any such blog post. It would be really helpful. I haven't had any luck finding blog post about sharing sessions between rails app. Thanks again for the write-up.
October 18th, 2008 at 06:32 PM Great article! How do you handle migrations using this approach?