Error Handling with Ruby on Rails
Tags: rails, react, ruby
Published: 2023-01-10 17:53:17

Naturally when we encounter an error in our code, Ruby will crash our program. Ruby on Rails with Active Record has developed a way to combat this so that developers can debug their code easier.

**Exceptions**

We all need rescued sometimes, Active Record is here at our aid with the help of raising exceptions for error handling. Exceptions in Ruby on Rails using Active Record gives developers a way to deal with unexpected events, or errors. So when we encounter an error, rather than crashing the whole program, we can use built in exceptions which will halt the program and help us to handle any errors that are thrown.

*Rescue_from*

Since all of our controllers inherit from our application controller in Ruby on Rails, that is where we will put our logic to handle our exceptions:

```
class ApplicationController < ActionController::API

rescue_from ActiveRecord::RecordInvalid, with: :unprocessable_entity_resp

rescue_from ActiveRecord::RecordNotFound, with: :not_found_resp

before_action :authorize

def current_owner
  @current_owner ||= Owner.find_by(id: session[:owner_id])    
end  

private 

def unprocessable_entity_resp(invalid)
  render json: {errors: invalid.record.errors.full_messages}, status: :unprocessable_entity
end

def not_found_resp  
  render json: {errors: "Not Found"}, status: :not_found
end

def authorize 
  render json: {errors:{Owner: "Not Authorized"}}, status: :unauthorized unless current_owner
end

```

As you can see in the code above, we use the "rescue_from" exception at the top level of our controller which is inherited from Active Record. The "with:" refers to a method that we create to handle the exceptions and to log our error messages. In the code above, the RecordNotFound exception is handled using our :not_found_resp method. Within that method we render our error message with JSON and provide that status of "not found". 

So to break this down in shorter terms, when you try to access data that cannot be found, Active Record will raise an exception and handle our errors with our "not_found_resp".

There is a second important key to this. Adding the exceptions to the methods we would like to apply it to. 

```
Class OwnersController < ApplicationController

    skip_before_action :authorize, only: :create

    def create
        owner= Owner.create!(owner_params)
        session[:owner_id] = owner.id
        render json: owner, status: :created
    end 

    def show
        render json: @current_owner, status: :ok
    end
 
    private

    def owner_params
        params.require(:owner).permit( :username, :password)
    end
end
```
 
In the Owners controller above, if you look at our "create" method you will notice the "!" after create. This is what allows us to raise an exception on this method. So if an error is encountered in this method, Active Record will refer back to our application controller and hit the method we created to handle the error it pertains to. Pretty easy, right?!

## Error Handling with Post Requests to our Front

Here I would like to discuss a bit about how our frontend 
(React) interacts with our backend (Ruby Rails) for error handling. Specifically with a POST request.

Let's say that we have an application that allows users to login. This would be a post request since we are sending data to our backend. We can handle this by using a fetch request that goes to a specified endpoint.

```
 const [errors, setErrors] = useState([])

 fetch('/api/login', {
      method: 'POST',
      headers: {
        "Content-Type": "application/json",
        "Accept": "application/json"
      },
      body: JSON.stringify(owner)
    }) 
    .then(res => {
      if(res.ok){
          res.json().then(owner => {
              loginUser(owner)
          })
      }else {
        res.json().then(json => setErrors(json.errors))
      }
  })
```

Our fetch request will go to '/api/login', and if everything goes well, it will send our owners information to our backend within our body and log our user in. However we all know that's not always the case. So what happens if we encounter an error?

Well, luckily we have implemented error handling in our backend to help with this. In the else statement from our React code above, you can see that we are taking the JSON response from our backend and setting it to our state so that we can access the errors from our backend, on our frontend. 

Below you can see that we are printing our errors in our return in a <h1> tag. So when an error occurs, it will print out that specific error to our user.


 return (
      <div className='primary'>
      <h1>{errors}</h1>
      <h1> Log In </h1> 
        <form onSubmit={ handleSubmit }>
          <div>
            <label htmlFor="username">Username: </label>
            <input type="text" name="username" id="username" onChange={ handleChange } value={ username } />
          </div>
          <div>
        <label htmlFor="password">Password: </label>
        <input type="text" name="password" id="password" value={password} onChange={handleChange} />
        </div> 
          <br></br>
          <input type="submit" value="Login" />
        </form>
      </div>
    )
  }

As you can see, error handling in Ruby on Rails with Active Record is quite simple and elegant. 

I hope this blog was helpful and can assist you in error handling for your future Ruby on Rails projects.