Peter Nixey
Peter Nixey

Reputation: 16555

How can I make my Angular requests be processed as format=JSON by Rails?

Whenever I make an API request from my angular front end to my Rails back end, the API calls are interpreted as content-type: :html. However I want them to be interpreted as content-type: :json

Inspecting the incoming request the content_type is correctly set to be "application/json" however the request.format evaluates to being :html

17:23:27 web.1  | (rdb:1) request.content_type
17:23:27 web.1  | "application/json"
17:23:31 web.1  | (rdb:1) request.format
17:23:31 web.1  | #<Mime::Type:0x007fb523405d00 @synonyms=["application/xhtml+xml"], @symbol=:html, @string="text/html">

What am I doing wrong, should I be forcing the headers on the client-side or do I have the wrong end of one of these sticks?

Edit

I guess that Rails is using the file ending to determine the required format - is there any way to make it respect the headers instead?

Upvotes: 1

Views: 876

Answers (2)

Peter Nixey
Peter Nixey

Reputation: 16555

As @mike pointed out it will ultimately make sense to setup a separate API namespace for the application in which things default to content-type: 'application/json'.

However that's a longer term shift for me and in the meantime, this is how I solved the problem.

Rails determines the format from the 'Accept' header

From this question, and this source code it's clear that Rails is using the Accept header to figure out the actual format.

You can set the accept header easily in Angular

It's easy enough to set the accept header in Angular

editorAppServices.factory('Magazine', ['$resource', 
  function($resource){ 
    return $resource('magazines/:toParam', {toParam: '@to_param'}, {
      query: {
        method: 'GET', params:{}, isArray:true
      },
      save: {
        method: 'PUT', headers: { 'Accept': 'application/json' }
      }
    })
  }])

And that's all there is to it.

Upvotes: 2

Mike Quinlan
Mike Quinlan

Reputation: 2882

Usually when you want to hook up an Angular application to a Rails project, it's best practice to create an api namespace for all of your angular resources. In your routes.rb file, you're going to want to do something like this:

# Set the default format to json
namespace :api, defaults: {format: :json} do
  # Edit and New routes are generally not required for RESTful JSON endpoints
  resources :my_json_resources, except: [:edit, :new]
  # Other resources
end

Then you can hit your routes without the json extension like so: /api/my_json_resources/:id. Setting the default on the route ensures that the endpoints will return JSON instead of HTML by default. Here's a cool tutorial (that might be a little outdated by now) that shows you how to integrate angular with rails 4. https://shellycloud.com/blog/2013/10/how-to-integrate-angularjs-with-rails-4

Also, note that the section where you set the CSRF headers is not recommended by the Angular documentation. For that please refer to this stack overflow post.

For Rails route namespace best practices, please refer to this documentation

Upvotes: 3

Related Questions