Rails respond_to block Explained

Written by alexa15 | Published 2018/03/14
Tech Story Tags: ruby-on-rails | rails

TLDRvia the TL;DR App

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.

The first step is to create a new project and generate a scaffold in Rails. Let’s take a look at some of our controller actions.

def index  @blogs = Blog.allend

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. If there is no handler it will raise an error. Credits to max.

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 }   endend

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, :xmlend

Not sure if this really works? Go on and test it using RSpec and FactoryBot!

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 inde    @blogs = Blog.all    respond_with(@blogs)  endend

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. Once you install it and generate a 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    }  endend

All the controller actions 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 taking the time to read it!

Originally published at kolosek.com on March 5, 2018.


Published by HackerNoon on 2018/03/14