Ruby on Rails Serialization: The Basics
Tags: rails, tutorial, flatironschool, activemodel
Published: 2022-12-08 08:10:43

Rails is a powerful Ruby framework that allows developers to focus on developing while handling most of the tedium work, i.e. database querying, in the background as long as you, the developer, follow the "convention-over-configuration" format. Rails' generators make following that format even easier.

For my current project, we want a User to be able to see all of their upcoming events. There a few ways to accomplish this and luckily Rails offers a couple simple solutions to us.

Note: Rails' conventions rely on the resource associations, In my [previous blog](https://dev.to/sassek70/a-beginners-guide-to-active-record-associations-2boi) I cover Active Record associations and some tips to help set them up correctly.

### USING INCLUDE: & EXCEPT:

When we query the database to find a User, we want to receive the User's information along with the events associated with that User. By default, the `show` action in the Users Controller will only return the User data:

```
#users_controller.rb
    def show
        user = User.find(params[:id])
        render json: user
    end

---

#server response
{
    "id": 2,
    "user": "kevin"
    "created_at": "2022-12-08T07:03:38.943Z",
    "updated_at": "2022-12-08T07:03:38.943Z",
}
```
If we add `include: :events` as part of the `show` action's render we will receive all events associated with that user.

```
#users_controller.rb

    def show
        user = User.find(params[:id])
        render json: user, include: :events
    end

---

#server response
{
    "id": 2,
    "user": "kevin",
    "created_at": "2022-12-08T07:03:38.943Z",
    "updated_at": "2022-12-08T07:03:38.943Z",
    "events": [
         {
            "id": 9,
            "name": "Muse",
            "venue": "Houston Center",
            "event_type": "concert",
            "created_at": "2022-12-08T06:09:39.617Z",
            "updated_at": "2022-12-08T06:09:39.617Z"
        },
        {
            "id": 5,
            "name": "Radiohead",
            "venue": "Atlanta-Center",
            "event_type": "concert",
            "created_at": "2022-12-08T06:09:39.596Z",
            "updated_at": "2022-12-08T06:09:39.596Z"
        }
    ]
}

```

Rails generators will, by default, add `t.timestamps` columns to your tables. We can use `except:` to prevent them from being returned by the server, however this will only exclude those keys from the top level resource, our events will still show those key/value pairs.

```
#users_controller.rb

    def show
        user = User.find(params[:id])
        render json: user, except: [:created_at, :updated_at], include: :events
    end

---

#server response
{
    "id": 2,
    "user": "kevin",
    "events": [
         {
            "id": 9,
            "name": "Muse",
            "venue": "Houston Center",
            "event_type": "concert",
            "created_at": "2022-12-08T06:09:39.617Z",
            "updated_at": "2022-12-08T06:09:39.617Z"
        },
        {
            "id": 5,
            "name": "Radiohead",
            "venue": "Atlanta-Center",
            "event_type": "concert",
            "created_at": "2022-12-08T06:09:39.596Z",
            "updated_at": "2022-12-08T06:09:39.596Z"
        }
    ]
}

```

We could work around that by nesting `include:` and `except:` statements, however, even with this simple example, that becomes very messy:

```
    def show
        user = User.find(params[:id])
        render json: user.to_json(except: [:created_at, :updated_at], include: [:events => {except:[:created_at, :updated_at]}])
    end

---

#server response
{
    "id": 2,
    "user": "kevin",
    "events": [
         {
            "id": 9,
            "name": "Muse",
            "venue": "Houston Center",
            "event_type": "concert",
        },
        {
            "id": 5,
            "name": "Radiohead",
            "venue": "Atlanta-Center",
            "event_type": "concert",
        }
    ]
}
```
If you really wanted to, you can keep chaining `include:` and `except:` as much as needed but Rails provides a better way.

### SERIALIZERS

Using Rails serializers allows us to clean up the Users Controller and control what data is being returned by the server.  You will have to make sure the gem is added to your Gemfile and installed. This gem is <u>not</u> included when running `rails new`

`gem 'active_model_serializers'`

Once installed, you can use `rails g resource` to create a model, controller and serializer at the same time, or you can also use `rails g serializer <name(singular)>` if you already have a model & controller.

Serialzers user `attributes` to define what keys are returned instead of `only:` or `except:`. They also make use of Active Record associations to include data from other tables. 

Returning to our User events example, we can simplify the Users Controller and add `attributes` and the necessary relationships to our serializers. 

```
#users_controller.rb
    def show
        user = User.find(params[:id])
        render json: user
    end

---

#user_serializer.rb
  class UserSerializer < ActiveModel::Serializer
    attributes :id, :username
    has_many :events
  end

---

#event_serializer.rb
  class EventSerializer < ActiveModel::Serializer
    attributes :id, :name, :venue, :event_type
  end

```

After updating all the files, our server response will be:


```
#server response
{
    "id": 2,
    "user": "kevin",
    "events": [
         {
            "id": 9,
            "name": "Muse",
            "venue": "Houston Center",
            "event_type": "concert",
        },
        {
            "id": 5,
            "name": "Radiohead",
            "venue": "Atlanta-Center",
            "event_type": "concert",
        }
    ]
}

```

Using serializers we can make our code cleaner and more efficient by following "separation of concerns" and Rails "convention over configuration". This is a simple example showing the basics of Rails Active Model Serializers

Further reading:
[Active Model Serializers Github](https://github.com/rails-api/active_model_serializers/tree/0-10-stable)