Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Database config in Ruby

#312

This patch allows a developer to configure their database via Ruby in addition to the existing database.yml. First, one specifies the path to the Ruby file:

config.database_configuration_file = 'config/database.rb'

Then, you set up your database in @database.rb@:

Rails::DatabaseSpecGenerator.map do |db|
  db.development :config => 
    {:adapter => 'sqlite3', 
     :database => 'db/development.sqlite3', 
     :timeout => 5000}
  db.test :config => 
    {:adapter => 'sqlite3', 
     :database => 'db/test.sqlite3', 
     :timeout => 5000}
  db.production :config => 
    {:adapter => 'sqlite3', 
     :database => 'db/production.sqlite3', 
     :timeout => 5000}
end

This patch does not yet generate config/database.rb by default, nor does it prevent you from using config/database.yml.

Reported by Adam Keys · June 3rd, 2008 @ 06:53 AM

State: wontfix
Milestone: none
Assigned to: nobody
Importance: none

Activity

  1. Adam Keys
    Adam Keys

    Really attach the patch this time.

    June 3rd, 2008 @ 05:58 PM

  2. Pratik
    Pratik
    • Assigned user set to Pratik

    June 3rd, 2008 @ 11:17 PM

  3. Cheah Chu Yeow
  4. Cheah Chu Yeow
    Cheah Chu Yeow

    I like this!

    I'm adding a patch based off Adam's one that would allow you to do something like this (I use defaults in YAML so this is needed for a Ruby version for me):

    Rails::DatabaseSpecGenerator.map do |db|
      db.defaults :config => {
        :adapter => 'mysql',
        :encoding => 'utf8'
      }
    
      db.development :config => {
        :database => 'ryokan_development'
      }.merge(db.defaults)
    end
    

    The syntax is not DSL-ish nor perfect but at least it's understandable ruby.

    Also some minor tweaks like removing the @@@returning@@@ block and using File.extname to check for file extensions.

    June 4th, 2008 @ 04:11 PM

  5. Adam Keys
    Adam Keys

    I'm curious what advantages db.defaults has something like this:

    Rails::DatabaseSpecGenerator.map do |db|
      defaults = {:adapter => 'mysql', :encoding => 'utf8'}
    
      db.development :config => defaults.merge(:database => 'ryokan_development'}
    end
    

    That said, I'm working on a somewhat different approach to this. Will post it here once I'm done.

    June 4th, 2008 @ 04:14 PM

  6. Pratik
    Pratik
    • Assigned user cleared.

    June 4th, 2008 @ 10:30 PM

  7. Cheah Chu Yeow
    Cheah Chu Yeow
    • Assigned user cleared.

    Ack sorry Adam you got me there. I was thinking of not doing it with a local var to stick to the DSL but I guess that's not very convincing. Looking forward to your different approach :)

    June 4th, 2008 @ 04:14 PM

  8. Adam Keys
    Adam Keys

    Just attached a reworked version. This time 'round, the database config hangs off of ActiveRecord itself. You can set it in your generic environment or a specific environment file. For example, in `config/environment.rb` :

      config.active_record.configure do |db|
        db.development do |setup|
          socket = %w{/tmp/mysql.sock /var/run/mysql.sock}.detect do |f|
            File.exists?(f)
          end
          setup.database = "test_app_#{Rails.env}"
          setup.adapter  = 'mysql'
          setup.socket = socket
          setup.credentials = "#{RAILS_ROOT}/config/credentials.rb"
        end
        
        db.production do |setup|
          socket = %w{/tmp/mysql.sock /var/run/mysql.sock}.detect do |f|
            File.exists?(f)
          end
          setup.database = "test_app_#{Rails.env}"
          setup.adapter  = 'mysql'
          setup.socket = socket
          # setup.credentials = "#{RAILS_ROOT}/config/credentials.rb"
        end
      end
    

    Or, in `config/environments/development.rb` :

    config.active_record.configure do |db|
      db.development do |setup|
        setup.database = 'test_app_development'
      end
    end
    

    Note you can set `credentials`. This loads a YAML or Ruby file with the database username/password information:

    username: root
    password: 
    
    username = 'root'
    password = ''
    

    You must use a credentials file in production, otherwise an exception is raised.

    If this version looks good, I'll start on app generator changes.

    June 6th, 2008 @ 07:05 AM

  9. Jeremy Kemper
    Jeremy Kemper

    Hey, that's pretty nice.

    What's the advantage of a DSL here (config builder) over, say, assigning a hash? e.g.

      config.active_record.databases = {
        :development => {
          :adapter => 'mysql',
          :socket => find_socket,
          :database => "#{test_app_#{Rails.env}",
          :credentials => "#{Rails.root}/config/credentials.rb"
        }, ...
    

    The blocks let you delay execution, but I'm not sure that's needed.

    June 6th, 2008 @ 07:18 AM

  10. Jeremy Kemper
    Jeremy Kemper

    yeah, pretend I wrote some valid Ruby too ^^^

    June 6th, 2008 @ 07:19 AM

  11. Adam Keys
    Adam Keys

    Jeremy: well in this case, having real methods makes it cleaner, IMHO, to do things like yell at the developer if they set a username/password in production mode. But really, I like the look of the block version better than a hash-y version.

    As an aside, I would love to not delay execution, but AR isn't loaded when environments are evaluated.

    June 6th, 2008 @ 01:01 PM

  12. Adam Keys
    Adam Keys

    I went ahead and did the generators. Here's what it looks like for a fresh app generated for MySQL:

      # Specify your database connections. You can partially configure your
      # your database here and then finish in an environment-specific file or
      # an initializer.
      config.active_record.configure do |db|
        
        # MySQL.  Versions 4.1 and 5.0 are recommended.
        #
        # Install the MySQL driver:
        #   gem install mysql
        # On Mac OS X:
        #   sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql
        # On Mac OS X Leopard:
        #   sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
        #       This sets the ARCHFLAGS environment variable to your native architecture
        # On Windows:
        #   gem install mysql
        #       Choose the win32 build.
        #       Install MySQL and put its /bin directory on your path.
        #
        # And be sure to use new-style password hashing:
        #   http://dev.mysql.com/doc/refman/...
        db.development do |setup|
          setup.encoding = utf8
          setup.username = root
          setup.password = 
          setup.socket = /tmp/mysql.sock
          setup.adapter = mysql
          setup.database = foo_development
        end
        
        # Warning: The database defined as "test" will be erased and
        # re-generated from your development database when you run "rake".
        # Do not set this db to the same as development or production.
        db.test do |setup|
          setup.encoding = utf8
          setup.username = root
          setup.password = 
          setup.socket = /tmp/mysql.sock
          setup.adapter = mysql
          setup.database = foo_test
        end
        
        # You cannot specify the username and password for your database directly
        # here. You need to add those details to a credentials file that looks
        # like this:
        #
        #  username = 'root'
        #  password = ''
        #
        # Specify the path to your credentials file below. For more info see 
        # http://rubyonrails.org/awesome_c...
        db.production do |setup|
          setup.encoding = utf8
          setup.credentials = "/path/to/your/credentials.rb"
          setup.socket = /tmp/mysql.sock
          setup.adapter = mysql
          setup.database = foo_production
        end
      end
    

    Looking for feedback on the code and/or copy.

    June 6th, 2008 @ 02:52 PM

  13. Adam Keys
    Adam Keys

    Updated patch to allow DRYer AR configuration. In environment.rb :

    config.active_record.configure do |db|
        
        db.encoding = utf8
        db.adapter = 'mysql'
        db.socket = /tmp/mysql.sock
        db.database = 'foo_development'
        
      end
    

    @development.rb@:

    config.active_record.connection.configure do |db|
      db.username = 'root'
      db.password = ''
      db.database = 'foo_development'
    end
    

    @production.rb@:

    config.active_record.connection.configure do |db|
      db.database = 'foo_production'
      db.credentials = '/path/to/your/credentials.rb'
    end
    

    environments.rb is loaded first. Environment-specific files overwrite anything set previously.

    June 8th, 2008 @ 05:54 PM

  14. James Cox
    James Cox

    I have to say that the credentials in a file means that rather than saving another file from getting checked in, what you are doing is just drying up database.yml - which is fine if it's an itch you want scratching :)

    to be honest- it might be more interesting drying it up properly. Why not get opinionated and append _dev/_prod/_test to the name of your db- so in env, set db.name = "foo" and the name of each db is inferred, unless you override and explicitly set in each env?

    June 11th, 2008 @ 04:16 PM

  15. Adam Keys
    Adam Keys

    @James yeah its completely possible to define the whole thing in environment.rb like so:

      config.active_record.connection.configure do |db|
        db.adapter  = 'mysql'
        db.encoding = 'utf8'
        db.database = "test_app_#{Rails.env}"
        db.socket = %w{/tmp/mysql.sock /var/run/mysql.sock}.detect do |f|
          File.exists?(f)
        end
        db.credentials = "#{RAILS_ROOT}/config/credentials.rb"
      end
    

    You can then override anything you want (adapter, credentials, etc.) in environment-specific files.

    June 11th, 2008 @ 04:31 PM

  16. Trevor Turk
    Trevor Turk

    I think this is a great direction, but I just wanted to note that using a hash might be more consistent with how email configuration works (e.g. config.action_mailer.smtp_settings)

    June 11th, 2008 @ 11:09 PM

  17. Adam Keys
    Adam Keys

    Trevor: indeed, I considered using a Hash. However, using a proper object makes it easier to yell at those who would explicitly set a username/password for their production database. ;)

    June 11th, 2008 @ 11:31 PM

  18. Chad Woolley
    Chad Woolley

    -1

    See comments on mailing list thread (which contains another -1 from another poster) for explanation.

    June 12th, 2008 @ 02:22 AM

  19. Steven Soroka
  20. Carsten Nielsen
  21. Wesley Moxam
    Wesley Moxam

    -1

    It might make for a nice plugin for those who desire such a feature.

    June 12th, 2008 @ 11:08 PM

  22. Pratik
    Pratik
    • State changed from new to wontfix
    • Tag set to activerecord, enhancement, patch, railties

    Closing till there is any further progress.

    August 21st, 2008 @ 11:53 AM