8

I am a newbie to AngularJS. I am using a rails application to expose data in json format. The data is to be used by angular app. The angular repo and the rails repo are completely different. The reason for different repositories is because I want my rails repo just to expose data using APIs which i can use in the angular app.

My rails controller is as below

class Api::V1::PhonesController < ApplicationController def index render json: Phone.all end def show render json: Phone.find(params[:id]) end ... end 

Now, when i visit 'localhost:3000/api/v1/phones', it returns me the json data for all the phones. When I visit 'localhost:3000/api/v1/phones/1', it returns the the json data for the phone with id 1. I validated the json data format using http://jsonlint.com/. Everything works fine till here.

My angularjs route file is as:

$routeProvider. when('/phones', { templateUrl: 'list.html', controller: 'PhoneListController' }). when('/phones/:id', { templateUrl: 'show.html', controller: 'PhoneShowController' }). otherwise({ redirectTo: '/phones' }); }]); 

My index.html in the angular repo has the list.html template embedded in it.

<html ng-app='phoneCatApp'> ... </html> <script type="text/ng-template" id="list.html"> This is the list template. </script> 

the code for the services.js is as:

var appServices = angular.module('appServices', []); phoneCatApp.factory('appServices', ['$http', '$q', function($http, $q){ var url = "http://localhost:3000/api/v1/"; //get all phones this.getPhones = function(){ var defered = $q.defer(); var listApi = url + "phones"; $http.jsonp(listApi).then(function(results){ defered.resolve(results); }, function(error){ defered.reject(error); }); return defered.promise; } return this; }]); 

The text in the script template is displayed as well when I visit '#/phones'. The problem is that 1) In chrome, following error is displayed when i inspect the page.

Refused to execute script from 'http://localhost:3000/api/v1/phones' because its MIME type ('application/json') is not executable, and strict MIME type checking is enabled. 

2) in firefox, the following error is getting displayed.

SyntaxError: missing ; before statement 

Thanks for the help.

1 Answer 1

7

Hey so I believe your problem is that your rails controller is returning JSON and NOT JSONP. Your controller has to explicitly specify a callback function, which can be specified by the request params.

See Handling jsonp in rails 3 controller for an example of returning JSONP from a rails controller

So your rails code would look like (argh my rails is very very rusty...):

class Api::V1::PhonesController < ApplicationController def index if params[:callback] format.js { render :json => {:phones => Phone.all.to_json}, :callback => params[:callback] } else format.json { render json: {:phones => Phone.all.to_json}} end end 

Then for the angular side, this answer should help you out: parsing JSONP $http.jsonp() response in angular.js

And I think your angular would then look like:

var appServices = angular.module('appServices', []); phoneCatApp.factory('appServices', ['$http', '$q', function($http, $q){ var url = "http://localhost:3000/api/v1/"; //get all phones this.getPhones = function(){ var defered = $q.defer(); var listApi = url + "phones?callback=JSON_CALLBACK"; $http.jsonp(listApi).then(function(results){ defered.resolve(results); }, function(error){ defered.reject(error); }); return defered.promise; } return this; }]); 
Sign up to request clarification or add additional context in comments.

5 Comments

getting error: "ActionController::InvalidCrossOriginRequest (Security warning: an embedded <script> tag on another site requested protected JavaScript. If you know what you're doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript embedding.)". So i disabled 'protect from forgery' and it works. Anyway can you please elaborate why it has to be this way?
Suppose there is a service which exports json data to lot many apps. Here, i cant modify the server code to consider the callback. The apps which are going to consume the json data need to handle it. how can that be done?
So this might be better as a separate question, perhaps even on securityexchange, but the docs are here: edgeapi.rubyonrails.org/classes/ActionController/… guides.rubyonrails.org/… (a good rails security guide)... Basically, implementing good csrf protections when you want to provide a JSONP endpoint is a little tricky and requires some careful thinking. Are the apps/consumers going to be on different domains than the REST server? A good start: stackoverflow.com/questions/613962/is-jsonp-safe-to-use
the apps/consumers are going to be different apps. My angular app theme is based on the official angularjs tutorial(phones catalogue) app. the only difference is that the tutorials use json files stored in the app to retrieve data whereas i am using a rails app to expose the data using APIs.
Honestly, if you're interested in having a secure app, I would use CORS (cross-origin-request-sharing) instead of JSONP. That way your REST server can actually choose specific domains to allow cross-domain requests from. Also - you can make use of angular's CSRF protections with tokens in the headers and you can check those tokens on your rails side.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.