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 myprevious blog 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, theshow
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 addinclude: :events
as part of theshow
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, addt.timestamps
columns to your tables. We can useexcept:
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 nestinginclude:
andexcept:
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 chaininginclude:
andexcept:
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 isnot included when runningrails new
gem 'active_model_serializers'
Once installed, you can userails g resource
to create a model, controller and serializer at the same time, or you can also userails g serializer <name(singular)>
if you already have a model & controller.
Serialzers userattributes
to define what keys are returned instead ofonly:
orexcept:
. 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 addattributes
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
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse