Introducing the "uses_connection" Rails plugin

This is a fairly simple but handy plugin that lets you specify which database connection to use on a per-model basis. It is useful when you have multiple applications sharing the same data.

Before uses_connection
The scenario below shows three separate applications having a common table among them. Lets say the ‘zip_codes’ table need to be updated every month with inserts and deletes, before installing the uses_connection plugin you will have to update the 3 tables separately, unless you have mysql round-robin enabled or another method for synchronizing the data (which most of the people don’t).


After installng uses_connection
The problem mentioned above is solved when using this plugin as you can see on the graph below. It allows you to connect all of the applications to a single database, therefore when updates are needed you only have to insert/delete data from one table instead of three.


Usage example
First lets create a ‘shared’ database configuration in config/database.yml:


shared:
  adapter: mysql
  database: shared_database
  username: user
  password: password
  host: dbs_host

Next we tell our model that it should connect the the ‘shared’ database and use the table there…


class ZipCode < ActiveRecord::Base
  # Uses the 'shared' database in all environments
  uses_connection :shared, :in => :all
end

... and voila, the next time you do


ZipCode.find(:first)

or any other interaction with the ZipCode model it will use the zip_codes table in your shared database! In other words, this is just a nicer way to use “Model.establish_connection(database)”.


Where to get it

You can get this plugin on GitHub at http://github.com/railsfreaks/uses_connection or by downloading this tar file uses_connection.tgz


Additional Documentation


# === options:
# :in:: Accepts an array or a single symbol describing the environment it
#       should use the connection for. Examples:
# 
#       class Book < ActiveRecord::Base
#         # Uses the 'shared' database in all environments
#         uses_connection :shared, :in => :all
# 
#         # Uses the 'shared' database in the production environment
#         uses_connection :shared, :in => :production
# 
#         # Uses the 'shared' database in the production and development environments
#         uses_connection :shared, :in => [:production, :development]
#       end
# 
# 
# :except:: Ignores the call if the current environment matches the array
#           or the single symbol used to describe the environment.
# 
#           class Book < ActiveRecord::Base
#             # Skips the plugin for the development environment
#             uses_connection :shared, :in => :all, :except => :development
# 
#             # Skips the plugin for the development and test environments
#             uses_connection :shared, :in => :all, :except => [:development, :test]
#           end



Comments

Sounds like a very interesting thing... but how does it perform when using this model in a join?
Comment by Maximilian Schulz on 05 07 2008 01:25 AM
Hey Maximilian, the plugin works seamlessly with joins or other types of "fancy" transactions. If you haven't tried yet I'd encourage you to do so.
Comment by Thiago Jackiw on 05 07 2008 08:35 AM
You know I have the opposite problem. I want to use the same code base but use different databases. Do you think I could use uses_connection to accomplish that with the following:

database.yml - will contain the database configurations for each customer models - then do the following:


class Book < ActiveRecord::Base
  customer_id = get_customer_id
  eval('uses_connection :#{customer_id}, :in => :production')
end
Comment by Tony on 05 08 2008 08:11 PM
Tony, you can certainly use the uses_connection plugin to accomplish what you need since you'll be using it to connect to different databases for each of your customers model. The 'concept' is the same when you use it to connect to a shared database.
Comment by Thiago Jackiw on 05 09 2008 12:21 PM
Tony, just fyi, you don't need the eval there

you can just do:

uses_connection :"#{customer_id}", :in => :production
Comment by coderrr on 05 11 2008 07:41 AM

Post a comment

(required)
(required)
(required)