Transform small tables with ActiveHash in Ruby on Rails

In a recent Ruby on Rails project, we needed to work with days of the week. We considered making a small table so we could fetch it, sort it, and join it to other tables as needed. But knowing that the days of the week do not change, we ruled out making a table for this data. We went with ActiveHash. With an ActiveHash class we can handle data in a manner similar to working with ActiveRecord classes, and since ActiveHash classes reside in memory, we get faster access than what is possible with a table.

We created the following ActiveHash class and placed it in our model’s folder (app/models). We gave it an instance method #tomorrow, and optionally, you can include other ActiveRecord-like things such as ‘alias’ and ‘scope’, as well.

class WeekDay < ActiveHash::Base
  include ActiveHash::Associations
  has_many :operating_hours

  self.data = [
	{
  	id: 1,
  	day: 'Monday',
  	rails_day_index: 1
	},
	{
  	id: 2,
  	day: 'Tuesday',
  	rails_day_index: 2
	},
	{
  	id: 3,
  	day: 'Wednesday',
  	rails_day_index: 3
	},
	{
  	id: 4,
  	day: 'Thursday',
  	rails_day_index: 4
	},
	{
  	id: 5,
  	day: 'Friday',
  	rails_day_index: 5
	},
	{
  	id: 6,
  	day: 'Saturday',
  	rails_day_index: 6
	},
	{
  	id: 7,
  	day: 'Sunday',
  	rails_day_index: 0
	}
  ]

  def tomorrow
	self.class.find((id % 7) + 1)
  end
end

Using our WeekDay class we have access to many ActiveRecord-like methods including the following:

WeekDay.all                     	# returns all objects
WeekDay.find_by(rails_day_index: 0) # returns the object for 'Sunday'

Once created, we can wire this to an ActiveRecord model with the following lines.

class OperatingHour < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to :week_day

  validates :week_day_id, presence: true
end

Using the ActiveHash::Associations allows access to the attributes of either the parent or child models, just as in ActiveRecord models.

In WeekDay we can access the related operating hours as follows:

week_day = WeekDay.find_by(rails_day_index: Date.today.wday)
hours_of_operation = week_day.operating_hours

Or from our OperatingHour we can access the related WeekDay as follows:

  operating_hour = OperatingHour.first
  day_of_week = operating_hour.week_day

We can create tests for ActiveHash classes similar to those we create for our ActiveRecord models. Here is an example:

require 'rails_helper'

RSpec.describe WeekDay, type: :model do
  describe '#tomorrow' do
	it 'returns Monday on Sunday' do
  	expect(WeekDay.find(7).tomorrow.day).to eq('Monday')
	end
  end
end

If later we decide to change our WeekDay class to be an ActiveRecord class with a database table, we can do so without having to rewrite the code we already have. Such flexibility and in-memory speed make ActiveHash a good choice for small data sets. One sacrifice is that it does not support all the features of ActiveRecord. This makes ActiveHash a good candidate for any project when the conditions are simple, as in this example.

Related Posts

Want to learn about the types of products we build?

Check out our projects

Like what you're seeing? Let's keep in touch.

Subscribe to Our Newsletter