0
votes

So I am trying to send a POST request with Content-Type: application/json from angular to my rails backend. I get the following error in console:

angular.js:12578 OPTIONS http://localhost:3000/api/student_create 404 (Not Found)

and

XMLHttpRequest cannot load http://localhost:3000/api/student_create. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8008' is therefore not allowed access. The response had HTTP status code 404.

Note the post request works properly when I use Content-Type: application/x-www-form-urlencoded

It also works in Postman with the application/json Content-Type set in the header.

Angular Controller:

.controller('View1Ctrl', function($scope, $http) {

  var data = {
    name: "name"
  };
  $http({
    url: 'http://localhost:3000/api/student_create',
    dataType: 'json',
    method: 'POST',
    data:data,
    headers: {
      "Accept": "application/json",
      "Content-Type": "application/json",
      "Access-Control-Allow-Origin": "*"
    }
  }).then(function(response) {
    console.log(response)
  }, function(error) {
    console.log(error)
  });

});

API controller (Rails):

class ApiController < ApplicationController
     before_action :set_headers
     skip_before_action :verify_authenticity_token

  def set_headers
    headers['Access-Control-Allow-Origin'] = '*'
    headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT'
    headers['Access-Control-Request-Method'] = '*'
    headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
    end
  def create_student
    student = StudentUser.new
    student.name= params[:name]
    student.save
    render json: "test".to_json #temporary
  end

route: post 'api/student_create' => 'api#create_student'

Edit: frontend is on http://localhost:8008, backend is on localhost:3000

2
what is the size of the data you're trying to post?alphapilgrim
It's just text. (the data object in the angular controller)Riyaz Shaikh
can you verify the object your sending is a valid json objectalphapilgrim
@alphapilgrim yeah it's valid, it's just the data objectRiyaz Shaikh
The Rails code needs a route for an OPTIONS request that replies with CORS headers.georgeawg

2 Answers

1
votes

Hi I too faced this problem when i was interacting Rails with Angular. After lot of research i found gem 'rack-cors' which solved this issue. You can follow its documentation here. Rails by default doesn't allow cross origin resource sharing. So basically it handles cross origin requests nicely.

Steps:

Install the gem:

gem install rack-cors

Or in your Gemfile:

gem 'rack-cors', :require => 'rack/cors'

application.rb file

module YourApp
  class Application < Rails::Application

    # ...

    # Rails 3/4

    config.middleware.insert_before 0, "Rack::Cors" do
      allow do
        origins '*'
        resource '*', :headers => :any, :methods => [:get, :post, :options]
      end
    end

    # Rails 5

    config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins '*'
        resource '*', :headers => :any, :methods => [:get, :post, :options]
      end
    end

  end
end
0
votes

Try the following, from How to Configure CORS Accept Headers in Rails API Application

So, even if your consumer is on “localhost:3000” and your provider is on “localhost:3001”, the response will be neglected unless your web service sets a permissive CORS policy. This policy is defined by the provider setting specific CORS headers in HTTP response that a consumer app (e.g. a browser) destined to enforce. For example, configuring these headers:

# in config / application.rb
config.action_dispatch.default_headers = {
  'Access-Control-Allow-Origin' => 'http://my-web-service-consumer-site.com',
  'Access-Control-Request-Method' => % w {
    GET POST OPTIONS
  }.join(",")
}

Per site:

Please note, that setting 'Access-Control-Allow-Origin' => '*' is highly discouraged, unless you are providing a public API that is intended to be accessed by any consumer out there.