Rails Database Connection with Block

I found myself needing to very quickly connect to an alternate database that was defined in my database.yml like so:

alternate_data:
    adapter: mysql
    database: alternate_database
    username: user
    password: pass
    host: localhost

I was accessing it with something similar to the following:

ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations["#{state}_data"])
results = connection.execute description_params[:extraction_sql];
#This wasn't actually hard coded, but this is just an example
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations["development"])

The problems with this was that I had to repeat this ugly code everywhere, and if there was an exception thrown while accessing the alternate database it would not revert back to the original before exiting.  So the next request to the server thought the default database was the alternate database.  What I decided would be useful would be to have an “establish_connection” method that accepted a block and handle these issues.

I am going to write about this because I planned to before realizing that in Rails 2.2 the exact same issue is solved already with a much better implementation (of course).  You can find how to solve this problem very elegantly in Rails 2.2 at http://www.igvita.com/2008/10/27/scaling-activerecord-with-mysqlplus/.

My implementation is much simpler and I hope that anybody stuck with Rails 2.1 (like me for now) or any previous version can use it temporarily until they can upgrade in the future.

I just wanted a simple block establish_connection so I could write code like the following:

   establish_temporal_database_connection("#{state}_data") do |connection|
      results = connection.execute description_params[:extraction_sql];
    end

It would reset the old database connection if something went wrong or when the block was over.

I’m just going to list a simple module that does this, if anybody wants this in plugin form that actually overrides establish_connection then it isn’t that difficult to turn this into that:

module ConnectionWithBlock  
  def self.extended(object)
    class << object
        extend ClassMethods
    end
  end
  module ClassMethods
    def establish_temporal_database_connection(configuration)
       #save the old connection
       previous_connection = ActiveRecord::Base.connection
       #establish connection handling a possible exception and going back to original connection
       begin
              ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[configuration.to_s])
              yield(ActiveRecord::Base.connection)
       rescue Exception => e
              raise e
       ensure
              ActiveRecord::Base.establish_connection(ConnectionSpecification.new(previous_connection.config, previous_connection.adapter_method))
       end   
     end
  end
end

Chase

blog comments powered by Disqus