Make ActiveRecord::Enum validation in Rails API application

Ben Mukebo
3 min readNov 14, 2023

--

As all know, Before Rails version 7.1 When you assign an incorrect value to any record that has an enum as type, it normally raises an ArgumentError as Server Error status: 500

And, for those who do know, a Rails enum is a way to define a set of allowed values for an attribute in a Rails model. Enums are stored as integers in the database but can be accessed and used in Ruby as symbols.

Enums were added to Rails in the 4.1 version, but until Rails 7.1, the ability to validate the enums was missing.

Let’s explore a practical scenario using a User model in a Rails API application. Consider the User model with various attributes, including a age_group column defined as an Enum which is expected to contain only the values specified here in my user.rb file:

# user.rb

class User < ApplicationRecord
...
enum age_group: { infants: 0, children: 1, adolescents: 2, adults: 3 }.freeze
end

If an incorrect value is assigned to the age_group column, Rails would raise an ArgumentError as shown below:

After doing more research to find a better way to catch and display a correct enum error, I found different approaches to doing so, but I felt they required more code logic to write than I wanted to find my own way to handle this more gracefully, and here it is.

Catching Enum Errors

In the Api::UsersController, we can implement a rescue block to catch the ArgumentError and provide a more user-friendly response; it is just simple. 😄

First, go to your controller in the create or update action:

# users_controller.rb
class Api::UsersController < ApplicationController
before_action :set_user, only: %i[show update destroy]
...

# PATCH/PUT /users/1
def update
if @user.update(user_params)
render_success_response('Profile updated successfully', @user)
else
render_unprocessable_entity_response(@user.errors)
end
rescue ArgumentError => e
render_unprocessable_entity_response(e.message)
end

...

private

# Use callbacks to share common setup or constraints between actions.
def set_user
@user = User.find(params[:id])
rescue ActiveRecord::RecordNotFound => e
render_not_found_response(e.message)
end

# Only allow a list of trusted parameters through.
def user_params
params.require(:user).permit(:username, :age_group, :remember_me, :terms_of_service)
end
end

The update action in `UsersController` handles profile modifications. Upon a successful update, it renders a successful response. If there are validation errors, it invokes `render_unprocessable_entity_response` with user errors. A rescue block addresses `ArgumentError` during updates, ensuring consistent feedback for enum-related errors.

Response Helper Module

Then, to maintain consistency in handling responses, a ResponseHelper module is created in app/controllers/concerns/response_helper.rb. This module includes methods for rendering success, unauthorized, not found, and unprocessable entity responses:

# response_helper.rb

module ResponseHelper
def render_success_response(message, data)
render json: {
success: true,
message: message,
data: data
}, status: :ok
end

# unprocessable_entity
def render_unprocessable_entity_response(error = 'Unprocessable entity')
render json: {
success: false,
errors: error,
}, status: :unprocessable_entity
end

def render_unauthorized_response(message = 'Unauthorized')
...
end

def render_not_found_response(message)
render json: {
success: false,
message: message,
data: nil
}, status: :not_found
end
end

Don’t forget to include the ResponseHelper module in your app/controllers/application_controller.rb:

# application_controller.rb

class ApplicationController < ActionController::API
include ResponseHelper

# Other configurations...
end

With these enhancements, your Rails API application will handle Enum errors more gracefully, providing clear and consistent responses to clients.

Written by Ben Mukebo.

I am a software developer, familiar with a variety of different web technologies and frameworks, and keen on always finding ways to explain things as simple as possible.

If this article has been helpful, please hit the 👏 button and share it with others! 🚀 to show how much you liked it! 😄

--

--

Ben Mukebo
Ben Mukebo

Written by Ben Mukebo

I’m a full-stack software developer and open-source enthusiast with a passion for web development, accessibility, pair programming, and remote work.

No responses yet