Read more

When reading model columns during class definition, you must handle a missing/empty database

Arne Hartherz
April 25, 2019Software engineer at makandra GmbH

When doing some meta-programming magic and you want to do something for all attributes of a class, you may need to access connection or some of its methods (e.g. columns) during class definition.

Illustration UI/UX Design

UI/UX Design by makandra brand

We make sure that your target audience has the best possible experience with your digital product. You get:

  • Design tailored to your audience
  • Proven processes customized to your needs
  • An expert team of experienced designers
Read more Show snapshot

While everything will be fine while you are working on a project that is in active development, the application will fail to boot when the database is missing or has no tables. This means that Raketasks like db:create or db:migrate fail on a freshly cloned project.

The reason is your environment.rb which is loaded for Raketasks and calls Rails.application.initialize! which in turn may/will evaluate classes. If one of those classes is tries to access its database connection, you will encounter fun errors such as:

  • PG::ConnectionBad (for missing databases on PostgreSQL)
  • ActiveRecord::StatementInvalid: PG::UndefinedTable (when database exists, but has no tables)

Generally speaking, evaluating model columns during class definition is not a bad thing, but you need to make it work when the model has no database or database columns yet. Example:

class Post < ApplicationRecord

    # Magically auto-strips all string attributes

    columns.each do |column|
      next if [:string, :text].exclude?(column.type)

      attribute_name =
      class_eval <<~RUBY, __FILE__, __LINE__ + 1
        def #{attribute_name}=(value)
  rescue PG::ConnectionBad, ActiveRecord::StatementInvalid
    # When the database does not exist at all or is missing a model's table,
    # accessing "columns" raises an error and the application fails to boot.
    # To allow calling "rake db:create" or "rake db:migrate" on an empty
    # database, we swallow such errors.


For MySQL, rescue Mysql2::Error, ActiveRecord::StatementInvalid might be fitting.

Posted by Arne Hartherz to makandra dev (2019-04-25 09:20)