Creating static data for your Rails application

Trésor Bireke

Introduction

Creating a new database table is great, but sometimes, you have a known set of values for which creating a new table feels like an overhead. That’s when static associations come into place.

What is static_association ?

Static association is a gem that adds basic ActiveRecord-like associations to static data in your Rails application. Instead of storing reference data in a database table, static_association allows you to define this data directly in your models. This can make querying for static data faster since it avoids database lookups.

Installation and Usage

Installing this gem is pretty straightforward.

Add gem "static_association" to your Gemfile, then run bundle and you should be ready to go.

Next, we create the static association class like this:

class RepaymentFrequency

  include StaticAssociation

  attr_accessor :name, :months_per_repayment_period, :selectable

  record id: 0 do |r|
    r.name = "Annually"
    r.months_per_repayment_period = 12
    r.selectable = true
  end

  record id: 1 do |r|
    r.name = "Quarterly"
    r.months_per_repayment_period = 3
    r.selectable = true
  end

  record id: 2 do |r|
    r.name = "Monthly"
    r.months_per_repayment_period = 1
    r.selectable = true
  end

  record id: 3 do |r|
    r.name = "Interest Only - Single Repayment on Maturity"
    r.months_per_repayment_period = 0
    r.selectable = true
  end
end

Currently, static_association only supports belongs_to associations. We can associate the static model with any active record model that has a foreign key of repayment_frequency_id.

class Loan < ActiveRecord::Base
  extend StaticAssociation::AssociationHelpers

  belongs_to_static :repayment_frequency
end

Here, the loans table should have repayment_frequency_id as a foreign key. Right now, static_association has a limited set of methods available; in the above example, the RepaymentFrequency class will gain .all.find.find_by_id, and .where methods.

You can look at the Github Repo to check if more methods have been added.

static_association vs enum

Both static_association and enum in Rails can be used for handling limited sets of values, but they differ in how they store and retrieve those values. Here’s a quick comparison to help you decide which one fits better for your use case:

1. enum in Rails
  • Pros:
    • Built-in Methods: Rails provides helper methods for querying, setting, and manipulating enums (e.g., status.active!User.where(status: :active)).
    • Simplicity: Enums are part of the Rails core, so they require no additional gems or configuration.
    • Scope & Validation: Automatically creates scopes and validations (e.g., User.active).
  • Cons:
    • Harder to Maintain: Changing or removing an enum value can be tricky. Since values are stored as integers, removing or reordering enum keys can break existing data.
    • Lack of Flexibility: Additional metadata or attributes cannot be easily associated with the enum values.
2. static_association Gem
  • Pros:
    • Flexibility: Since values are stored in a separate table, you can easily associate additional metadata or attributes (e.g., descriptions, codes) with each value.
    • Easier to Maintain: Adding or changing values doesn’t require a migration, and you don’t run into issues with removing or renaming values as you do with enums.
    • Querying Power: Since it’s a true association, you can easily join on the lookup table, query it, and use ActiveRecord’s association methods.
    • Readable: Rather than storing an integer, your database stores a meaningful reference (foreign key), which can make it easier to work with directly at the database level.
  • Cons:
    • Overhead: Adds additional complexity with the need to maintain a lookup table and relationships.
    • Performance: Slightly more overhead with joins compared to enum as it requires querying a related table.

Using the example from the usage section, if you wanted to prevent a repayment_frequency from being selected, you’d just have to update the selectable attribute to false. Using static association, we can add other attributes like a different interest rate for each repayment frequency without breaking the existing code or needing much refactoring.

  record id: 1 do |r|
    r.name = "Quarterly"
    r.months_per_repayment_period = 3
    r.selectable = true
    r.interest_rate = 2.5
  end

Hopefully, that comparison makes it easier to decide which one fits your use case.