Shackles allows multiple database environments and environment overrides to ActiveRecord, allowing least-privilege best practices.
gem 'shackles' to your Gemfile (tested with Rails 2.3 and 3.2)
There are two major use cases for shackles. The first is for master/slave(/deploy) environments. Using a slave is as simple as adding a slave block (underneath your main environment block) in database.yml, then wrapping stuff you want to query the slave in Shackles.activate(:slave) blocks. You can extend this to a deploy environment so that migrations will run as a deploy user that permission to modify schema, while your normal app runs with lower privileges that cannot modify schema. This is defense-in-depth in practice, so that if you happen to have a SQL injection bug, it would be impossible to do something like dropping tables.
The other major use case is more defense-in-depth. By carefully setting up your environment, you can default to script/console sessions for regular users to use their own database user, and the slave.
Example database.yml file:
production: adapter: postgresql username: myapp database: myapp host: db-master slave: host: db-slave deploy: username: deploy
Using an initializer, you can achieve the default environment settings (in tandem with profile changes):
if ENV['RAILS_DATABASE_ENVIRONMENT'] Shackles.activate!(ENV['RAILS_DATABASE_ENVIRONMENT'].to_sym) end if ENV['RAILS_DATABASE_USER'] Shackles.apply_config!(:username => ENV['RAILS_DATABASE_USER']) end
Additionally in Ruby 2.0+ you can include Shackles::HelperMethods and use several helpers to execute methods on specific environments:
class SomeModel include Shackles::HelperMethods def expensive_read_only ... end shackle_method :expensive_read_only, environment: :slave def self.class_level_expensive_read_only ... end shackle_class_method :class_level_expensive_read_only, environment: :slave # helpers for multiple methods are also available shackle_methods :instance_method_foo, :instance_method_bar, environment: :slave shackle_class_methods :class_method_foo, :class_method_bar, environment: :slave end