Recientemente tuve que sumergirme en AngularJS en un sitio de Rails que estábamos construyendo para un cliente. Además del contenido de la página, el cliente tiene ciertas páginas que muestran titulares que enlazan a fuentes externas pero que se extraen en nuestro stack de Rails a través de una tarea rake que se ejecuta periódicamente. El sitio debe ser almacenado en caché intensamente a través del uso de una CDN, como CloudFront, pero para mantener los titulares actualizados, utilizamos AngularJS (porque el cliente estaba familiarizado con él, lo que facilitaba su mantenimiento) para consultar directamente el stack de rails sobre los últimos titulares.
Esto requirió hacer las cosas de manera transversal, ya que el dominio del sitio apuntaría a CloudFront. No había escrito una API de Rails que devolviera JSONP ni un servicio de AngularJS antes, así que tuve que explorar un poco y esto es lo que funcionó para mí. (También puedes leer el gist.)
Nota: Si no estás familiarizado con JSONP, esto no tendrá mucho sentido. Lee esto.
Servicio de AngularJS
AngularJS tiene el concepto de servicios, que son solo singletons que se pueden usar donde sea necesario. En nuestro caso, puedes pensar en nuestro servicio de titulares como el cliente de la API de titulares que envuelve nuestras llamadas JSONP en una sintaxis más simple y centralizada. AngularJS proporciona algunos servicios por defecto, pero puedes escribir los tuyos propios. De hecho, podríamos haber usado el servicio $resource
integrado en lugar de escribir el nuestro, sin embargo, tuve algunos problemas para que JSONP funcionara y quería entender mejor los componentes de bajo nivel de AngularJS, así que escribí el mío:
angular.module('app')
.factory('HeadlineService', ['$http',
function($http) {
'use strict';
var BASE_URL = "<%= [App.settings.api_base_url, '/services/headlines'].join %>",
CALLBACK_STRING = "?callback=JSON_CALLBACK";
return {
getHeadlines: function(){
return $http.jsonp(BASE_URL + CALLBACK_STRING)
},
getHeadlineForId: function(id){
return $http.jsonp(BASE_URL + "/" + id + ".json" + CALLBACK_STRING)
}
}
]);
El servicio anterior usa el servicio $http
integrado, que simplemente proporciona un wrapper AJAX, para hacer solicitudes a nuestro backend de rails para obtener titulares. Algunas cosas a tener en cuenta:
- Devuelve un objeto con 2 funciones:
getHeadlines
ygetHeadlineForId
. Luego podemos usar estas funciones como atajos para hablar con la API de Rails en nuestros controladores de AngularJS. - Usa JSONP. Nota que estamos usando
$http.jsonp
y estamos pasando una cadena de consulta?callback=JSON_CALLBACK
. AngularJS reemplaza la cadenaJSON_CALLBACK
con el nombre de una función de callback que crea para ti. - Usa un dominio diferente. Bueno, eso se espera ya que estamos haciendo JSONP, pero lo logramos agregando una extensión
.erb
al archivo y usando lo que establezcamos paraApp.settings.api_base_url
en la aplicación de Rails como el dominio con el que AngularJS debe hablar. Recuerda que esto es para eludir la capa de caché de la CDN para que nuestros titulares sean siempre los más recientes.
Controlador de AngularJS
Con nuestro HeadlinesService
construido, ahora podemos usar las 2 funciones que devuelve en nuestra aplicación de AngularJS:
angular.module('app')
.controller('HeadlinesCtrl', ['$scope', 'HeadlineService',
function($scope, HeadlineService) {
'use strict';
HeadlineService.getHeadlines().success(function(data, status, headers, config){
$scope.headlines = data;
HeadlineService.getHeadlineForId(data[0].id).success(function(data){