# StoreModel

> A Ruby gem to simplify working with JSON database columns which are used to store various unstructured data.

- URL: https://evilmartians.com/opensource/store-model
- GitHub: https://github.com/DmitryTsepelev/store_model
- Authors: Dmitry Tsepelev

---

store_model is a Ruby gem that was created to simplify working with JSON database columns which are used to store various unstructured data. It wraps plain JSON to an ActiveRecord-like model, which looks more familiar to Rails developers. Type conversions are also included.

The StoreModel Ruby gem allows you to wrap JSON-backed database columns with ActiveModel-like classes.

- **Powered with [Attributes API](https://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html)**. You can use a number of familiar types or write your own.
- **Works like ActiveModel**. Validations, enums and nested attributes work very similar to APIs provided by Rails.
- **Follows single responsibility principle**. Keeps the logic around the data stored in a JSON column separated from the model.
- **Born in production**.

```ruby
class Configuration
  include StoreModel::Model

  attribute :model, :string
  enum :status, %i[active archived], default: :active

  validates :model, :status, presence: true
end

class Product < ApplicationRecord
  attribute :configuration, Configuration.to_type
end
```

## Why should I wrap my JSON columns?

Imagine that you have a model `Product` with a `jsonb` column called `configuration`. This is how you likely gonna work with this column:

```ruby
product = Product.find(params[:id])
if product.configuration["model"] == "spaceship"
  product.configuration["color"] = "red"
end
product.save
```

This approach works fine when you don't have a lot of keys with logic around them and just read the data. However, when you start working with that data more intensively—you may find the code a bit verbose and error-prone.

For instance, try to find a way to validate `:model` value to be required. Despite of the fact, that you'll have to write this validation by hand, it violates single-repsponsibility principle: why parent model (`Product`) should know about the logic related to a child (`Configuration`)?

**Read more about the motivation:**

*Read also Evil Martians' article*: https://evilmartians.com/chronicles/wrapping-json-based-active-record-attributes-with-classes
