Rails respond_to block Explained

When you start your first Rails application you might think that **controller actions** are only capable of rendering HTML. So why and how to use a **respond_to** block? Here, we will show you how handy **respond_to** blocks can be. 
## respond_to 
The first step is to create a new project and generate a [scaffold](https://kolosek.com/rails-scaffold/) in Rails. Let's take a look at some of our controller actions.

```
def index
  @blogs = Blog.all
end
```
As you can see, `index` action does not have a `respond_to` block. So, this will work when just rendering an HTML. But what if, however, a client asks to get the page in TEXT format? It will lead to an **exception**:

`ActionView::MissingTemplate (Missing template blogs/index ... with { ... :formats=>[:text], ...})`
>*Rails goes through the registered formats and tries to find a compatible format for the [MIME type in the request](https://github.com/rails/rails/blob/4f6f43338f7e4d3a3fe5ad86d024007ee95a7389/actionpack/lib/action_dispatch/http/mime_types.rb). If there is no handler it will raise an error. Credits to [max](https://stackoverflow.com/questions/30600864/rails-respond-to-blocks-and-format/30601162#30601162).*
>

Instead of telling our clients that the **file is missing**, we want to tell them that the **requesting format is not supported**. You could add a `respond_to` block to your `index` action:

```
def index
  @blogs = Blog.all

  respond_to do |format|
    format.html # index.html
    format.js   # index.js
    format.xml { render xml: @blogs }
  end
end
```

After the change, the client will get `406 error` when the format is not supported. Also, your `index` action will respond to two new formats: js and xml.

If you need a simple and quick way to render your objects, you can take this **shortcut**, it works in the same way as the example above:

```
def index
  @blogs = Blog.all
  respond_to :html, :json, :xml
end
```
Not sure if this really works? Go on and test it using [RSpec](https://kolosek.com/rails-rspec-setup/) and [FactoryBot](https://kolosek.com/factory-girl-associations/)!
## Responding to the same format
It’d be nice if you could have a `respond_to` that would affect the *entire* controller. Usually, each action in your controller can work with the same formats, you can achieve this by using `respond_with`. Here is an example of how to implement it:

```
class BlogController < ApplicationController
  respond_to :html, :json, :xml

  # GET /blogs
  # GET /blogs.json
  # GET /blogs.xml
  def index
    @blogs = Blog.all
    respond_with(@blogs)
  end
end
```
**If you need more control and want to be able to have a few actions that act differently, you can always use a full respond_to block.**

In Rails 4.2, `respond_with` is no longer included.  But you can get it back if you [install the responder gem](https://kolosek.com/rails-bundle-install-and-gemfile/). Once you install it and generate a [Rails scaffold](https://kolosek.com/rails-scaffold/), the generator will create controllers using `respond_with` instead of `respond_to`.

```
class BlogController < ApplicationController
  before_action :set_blog, only: [:show, :edit, :update, :destroy]
  respond_to :html, :json
  
  def index
    @blogs = Blog.all
    respond_with(@blogs)
  end
  ...
end
```
## Format ALL or Format ANY?
If you’d like to specify a `respond_to` to render something for all formats while keeping other options untouched, you can always use **format.all** in the following way:

```
respond_to do |format|
  format.csv { render_csv }
  format.all { render_404 }
end
```
Use **format.any** if you want to specify a common block of different formats:

```
def index
  @blogs = Blog.all

  respond_to do |format|
    format.html
    format.any(:xml, :json) { 
      render request.format.to_sym @blogs 
    }
  end
end
```
All the [controller actions](https://kolosek.com/rspec-controller-test/) need to be tested to make sure they work as intended!
## Defining custom MIME type 
If you need to use a MIME type which isn't supported by default, you can register your own handlers in `config/initializers/mime_types.rb`: 

```
Mime::Type.register "text/markdown", :markdown
```

That's it for this article! Thank you for your time reading it!

**Originally published on [Kolosek Blog](https://kolosek.com/rails-respond_to-block/).**