How to work with JSONB column in pure Ruby on Rails

JSONB columns are incredibly versatile and efficient and are an excellent way to add flexibility to your application database. This guide will explore how to use JSONB columns in your Ruby on Rails application with read, write, setting defaults and validation.

What is a JSONB Column?

Before we dive into the practicalities, let's explore what a JSONB column is. PostgreSQL introduced the JSONB datatype in version 9.4 as an improvement over the previously implemented JSON datatype. It provides the powerful ability to store structured, complex data within a single database column.

Using JSONB in Ruby on Rails

To interact with JSONB columns in Ruby on Rails, we use the built-in store_accessor. It creates methods to directly access stored data, just like you'd do with any other attribute. Consider this sample code:

module SettingKeysRequirable
  attr_reader :required_settings_keys

  def set_required_settings_keys(keys)
    @required_settings_keys = keys
    store_accessor :settings, @required_settings_keys
    validates_presence_of @required_settings_keys
  end
end

In this setup, we define the set_required_settings_keys function, which not only marks certain keys on the settings (a JSONB column in our case) as required, but also makes sure those keys are present using Rails' validates_presence_of function. The behavior is stored in an instance variable and read via attr_reader.
With the SettingKeysRequirable module in place, it's time to leverage its utility in our user model.

class User < ApplicationRecord
  extend SettingKeysRequirable
  set_required_settings_keys %w(url login_url my_default_key) # we have 'settings' column as a jsonb in User table in this example

  def set_default_settings!(current_domain: 'www.abc.pl')
    self.settings = {
      my_extra_stuff: 'my_extra_value',
      my_default_key: 'my_default_value',
      login_url: "#{current_domain}/login",
    }
  end
end

In the User model, we've defined a few keys (url, login_url, and my_default_key) as required settings. This clarification means they have to be present in the settings of each User record. Note that the settings column itself must be of type JSONB.

Working with records

Next, let's use these newly defined methods to interact with our user records:

id = User.new
id.login_url
# => nil
id.set_default_settings!
id.login_url
# => "www.abc.pl/login" # loaded default settings
id.url
# => nil
id.valid?
# => false
id.errors.full_messages
# => ["Url can't be blank"]
id.url = 'www.blabla.pl' # access directly to attribute from JSONB settings column
id.valid?
# => true
id.save!
# => true

This example shows that we can read from and write to our JSONB settings column just like any other attribute.

Summary

Working with JSONB in Ruby on Rails is an efficient and flexible way to store and manipulate structured data. It allows us to define and validate keys directly within a JSONB hash, simplifying and streamlining our coding practices. Dive in and give it a try!

Happy Coding!