Skip to navigation

Avoid DB calls when setting up your environment

Published December 09, 2006

As one of my projects has increased in complexity I’ve started to use the environment.rb and the other specific environments to set up mocks and other tidbits.

For example, here I’m setting the current Locale based on RegionPreference, which is an ActiveRecord model, from within environment.rb:


Locales.current = Locales.locale_for_timezone(RegionPreference.find_or_initialize.timezone) rescue nil

This was all fine and dandy until I tried to set the app on a new machine.


$ rake db:schema:load RAILS_ENV=staging
(in /usr/home/voicebox)
rake aborted!
SQLite3::SQLException: no such table: region_preferences:
SELECT * FROM region_preferences LIMIT 1

What happened?

db:schema:load depends on the environment task, which loads your Rails environment. The same goes for db:migrate. My environment was being loaded and trying to call the database before db:schema:load could do it’s job.

Lesson: Accessing your database from within your environment set up is evil.

You can’t assume your database exists, or is an up-to-date version, when your environment’s are being executed.

The fix? Moving the code to the model where it should have been in the first place.


module Locales
  def self.current
    @@current ||= locale_for_timezone(RegionPreference.find_or_initialize.timezone)
  end
end

Archived comments

Comments were previously allowed on articles. Though no new comments are being accepted you can see the old comments below.

  1. James Adam

    I’m not sure that I’d agree it’s evil to do these things in environment/* – just that Rails doesn’t support it. Here’s hoping that 2.0 will bring a reconsidered startup routine that makes what seems natural, actually possible :)

  2. Brian Hartin

    By extension, this means that you shouldn’t reference any models either, if your models do any ‘class-load time’ database calls, e.g.


    class StatusCode < ActiveRecord::Base

    1. Define constants representing each status
      APPROVED = self.find(…)
      DENIED = # …

    2. end

I’m currently thinking on the best way to solve that one.

Previously: A clean slate, Edge Rails recipe

Next up: WebConserve

Thoughts

toolmantim

I’m Tim Lucas, a user experience developer currently in Sydney Australia.

I occasionally write, snap photos, present on various technical topics, tweet my going-ons, share teh codes and post tidbits to the scrapbook.

Most recently I published Simplifying ticket sales on sydneyoperahouse.com (February 16, 2010)

Work with me via Agency Rainford, or shoot an email to and say hello.

Powered by your inner voice