Yianna Kokalas

Mime Responses in Rails

01 Jun 2016

Basic action

def index
  @posts = Posts.all

  render :index
end

When a client makes a request it generally will expect HTML as response to an action call. What if the client would expect json? The following example uses respond_to to determine a match for this service.

def index
  @posts = Posts.all

  respond_to do |format|
    format.html { render xml: @post }
    format.json { render json: @post }
    format.xml { render xml: @post }
  end
end

Here we are going to implement a create action for a new post. Lets pretend we’re using strong params along with devise for a current_user helper.

def create
  @user = current_user
  @post = @user.post.find_or_create_by(post_params)

  redirect_to post_path @post
end

To be able to send back the appropriate format we once again use a respond_to block.

def create
  @user = current_user
  @post = @user.post.find_or_create_by(post_params)

  respond_to do |format|
    format.html { redirect_to (post_path @post) }
    format.js
    format.json { render json: @post.to_json(include: @user) }
  end
end

If the client wants HTML we redirect them to the post list. If they want JavaScript, then it’s an ajax request and we render the JavaScript template associated with this action. Lastly, if the client wants JSON, we render the created person as JSON, but with a difference. We will also include the current user in the response. Sort of like this.

{
  posts: [
    {
      id: 1,
      title: "A new post!"
      description: "the greatest post ever."
      user: {
        id: 99,
        name: 'Sam'
      }
    }
  ]
}

What happens if some of the responses are being repeated? To be more DRY you can do this.

def index
  @posts = Post.all

  respond_to do |format|
    format.html
    format.any(:json, :xml) { render request.format.to_sym => @posts }
  end
end

The format in respond_to is actually an object of ActionController::MimeResponds::Collector class. This object works as a container to store available responses that can be called on by any of the mime-type-specific methods such as html, xml etc.

It makes a subsequent call to negotiate_format(request) on the backend and enables the Collector to determine which mime-type specifically it should respond with. When it finds a match it calls response.

Tweet me @yonk_nyc if you like this post.

Tweet