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
).
- Built-in Methods: Rails provides helper methods for querying, setting, and manipulating enums (e.g.,
- 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.