No release in over 3 years
Eliminates "Undeclared attribute type for enum" errors that occur when running migrations with multiple enum columns added in separate migrations. Automatically declares missing enum attributes as integers, preventing migration failures.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

~> 2.0
~> 5.0
~> 13.0
>= 2.1

Runtime

>= 7.2
 Project Readme

EnumErrorsAway

CI Gem Version

Fix Rails 7.2+ enum migration failures - EnumErrorsAway eliminates "Undeclared attribute type for enum" errors that break migrations when enum columns are added in separate migrations.

The Problem

Rails 7.2+ requires enum attributes to be declared with a type when they don't have a corresponding database column. This causes migration failures in a common scenario:

# Your model defines multiple enums
class Organization < ApplicationRecord
  enum :status, { active: 0, inactive: 1 }
  enum :billing_plan, { free: 0, paid: 1 }
end

# db/migrate/20240101_add_status_to_organizations.rb
add_column :organizations, :status, :integer

# db/migrate/20240201_add_billing_plan_to_organizations.rb
add_column :organizations, :billing_plan, :integer

When running migrations from scratch, the first migration fails:

ArgumentError: Undeclared attribute type for enum 'billing_plan' in Organization.
Enums must be backed by a database column or declared with an explicit type via `attribute`.

This happens because:

  1. The first migration runs and loads the Organization model
  2. The model defines both status AND billing_plan enums
  3. But the billing_plan column doesn't exist yet (it's added in the second migration)
  4. Rails 7.2+ throws an error

This is especially problematic when:

  • Running migrations from scratch (new development environments, CI/CD, test databases)
  • Adding new enums over time in separate migrations
  • Migrating legacy applications to Rails 7.2+
  • Working with large teams where different developers add enums in different migrations

The Solution

EnumErrorsAway automatically handles this for you. Just add the gem and your enums work again - no code changes required!

The gem:

  • Automatically declares missing enum attributes as integers
  • Preserves legitimate enum errors (method collisions, invalid values, etc.)
  • Zero configuration required - works out of the box
  • Type-safe - includes RBS type definitions for Steep/TypeProf
  • Fully tested - comprehensive test suite
  • Rails 7.2+ compatible

Installation

Add this line to your application's Gemfile:

gem 'enum_errors_away'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install enum_errors_away

Usage

Once installed, the gem automatically works for all ActiveRecord models. No configuration needed!

Before (Rails 7.2+ without this gem):

class Organization < ApplicationRecord
  enum :status, { active: 0, inactive: 1 }           # Added in first migration
  enum :billing_plan, { free: 0, paid: 1 }            # Added in second migration
end

# Running the first migration fails because billing_plan column doesn't exist yet!
# You'd need to manually add: attribute :billing_plan, :integer

After (with this gem):

class Organization < ApplicationRecord
  enum :status, { active: 0, inactive: 1 }
  enum :billing_plan, { free: 0, paid: 1 }
end

# Migrations run successfully - attributes are automatically declared as integers
# No manual attribute declarations needed!

Features

All Enum Syntaxes Supported

class User < ApplicationRecord
  # Hash syntax
  enum :status, { active: 0, inactive: 1 }

  # Array syntax
  enum :role, [:admin, :user, :guest]

  # With options
  enum :access_level, { basic: 0, premium: 1 }, prefix: true

  # With Rails 7.2+ options
  enum :visibility, { public: 0, private: 1 }, scopes: false
end

Legitimate Errors Still Raised

The gem only suppresses the "Undeclared attribute type" error. Other enum errors are preserved:

class Organization < ApplicationRecord
  enum :status, { available: 0, unavailable: 1 }

  # This will correctly raise an error about method collision
  enum :availability, { available: 0, unavailable: 1 }
  # ArgumentError: already defined by another enum
end

Type Safety with RBS

The gem includes RBS type definitions for Steep and TypeProf:

# Your types are automatically available
module EnumErrorsAway
  def self.enabled?: () -> bool
  def self.configure: () { (singleton(EnumErrorsAway)) -> void } -> void
end

Configuration

Disabling the Gem

You can disable the gem globally or conditionally:

# config/initializers/enum_errors_away.rb
EnumErrorsAway.configure do |config|
  config.enabled = false
end

# Or conditionally
EnumErrorsAway.enabled = Rails.env.production?

Checking Status

EnumErrorsAway.enabled?  # => true

Real-World Example

Here's the typical scenario this gem solves:

# app/models/organization.rb
class Organization < ApplicationRecord
  enum :status, { active: 0, inactive: 1 }        # Added May 2024
  enum :billing_plan, { free: 0, paid: 1 }        # Added June 2024
  enum :notification_preference, { email: 0, sms: 1, both: 2 }  # Added July 2024
end

# db/migrate/20240501_add_status_to_organizations.rb
class AddStatusToOrganizations < ActiveRecord::Migration[7.2]
  def change
    add_column :organizations, :status, :integer, default: 0
  end
end

# db/migrate/20240601_add_billing_plan_to_organizations.rb
class AddBillingPlanToOrganizations < ActiveRecord::Migration[7.2]
  def change
    add_column :organizations, :billing_plan, :integer, default: 0
  end
end

# db/migrate/20240701_add_notification_preference_to_organizations.rb
class AddNotificationPreferenceToOrganizations < ActiveRecord::Migration[7.2]
  def change
    add_column :organizations, :notification_preference, :integer, default: 0
  end
end

Without this gem: When a new developer runs rails db:migrate from scratch, the first migration fails because the model references enums that don't have columns yet.

With this gem: All migrations run successfully. The gem automatically declares the missing enum attributes, and everything works seamlessly.

How It Works

  1. Hooks into ActiveRecord - Uses a Railtie to integrate with Rails initialization
  2. Extends enum method - Wraps the standard enum method via ActiveSupport::Concern
  3. Pre-declares attributes - Before defining an enum, checks if the attribute exists in the database; if not, declares it as :integer
  4. Handles migration timing - Gracefully handles database connection errors during migrations
  5. Preserves error handling - Only catches "Undeclared attribute type" errors; all other enum errors pass through
  6. Zero runtime performance impact - Only runs during class definition, not during model usage

Compatibility

  • Ruby: 3.1+
  • Rails: 7.2+

Development

# Install dependencies
bundle install

# Run tests
bundle exec rake test

# Run type checks
bundle exec steep check

Testing

The gem includes a comprehensive test suite covering:

  • Enums without database columns
  • Enums with database columns
  • Multiple enum syntaxes (hash, array, with options)
  • Error handling (ensures legitimate errors aren't suppressed)
  • Configuration and enable/disable functionality
  • Integration with real Rails models

Run tests with:

bundle exec rake test

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/sampokuokkanen/enum_errors_away.

License

The gem is available as open source under the terms of the MIT License.

Credits

Created to solve the Rails 7.2+ enum declaration requirement while maintaining backward compatibility with existing codebases.