Representación de JSON en el controlador

103

Estaba leyendo un libro y en un capítulo sobre controladores cuando habla sobre renderizar cosas, para JSON tiene un ejemplo como este pero no entra en detalles, por lo que no pude entender la imagen más grande en la que encaja este ejemplo:

render :json => @projects, :include => tasks

Y también algún ejemplo con JSONP usándolo con funciones de devolución de llamada:

render :json => @record, :callback => 'updateRecordDisplay'

¿Alguien puede explicar esto?

buena mano
fuente

Respuestas:

127

Normalmente devolverá JSON porque:

A) Está construyendo parte / toda su aplicación como una aplicación de página única (SPA) y necesita su JavaScript del lado del cliente para poder extraer datos adicionales sin recargar completamente la página.

o

B) Está creando una API que consumirán terceros y ha decidido utilizar JSON para serializar sus datos.

O, posiblemente, esté comiendo su propia comida para perros y haciendo ambas cosas

En ambos casos render :json => some_data, JSON-ify los datos proporcionados. La :callbackclave en el segundo ejemplo necesita un poco más de explicación (ver más abajo), pero es otra variación de la misma idea (devolver datos de una manera que JavaScript pueda manejar fácilmente).

¿Por qué :callback?

JSONP (el segundo ejemplo) es una forma de sortear la Política del mismo origen que forma parte de la seguridad integrada de cada navegador. Si tiene su API en api.yoursite.comy estará sirviendo su aplicación fuera de services.yoursite.comsu JavaScript, no podrá (de forma predeterminada) realizar XMLHttpRequestsolicitudes (XHR - también conocido como ajax) desde serviceshasta api. La forma en que las personas se han escabullido de esa limitación (antes de que se finalizara la especificación Cross-Origin Resource Sharing ) es enviando los datos JSON desde el servidor como si fuera JavaScript en lugar de JSON ). Por lo tanto, en lugar de enviar de vuelta:

{"name": "John", "age": 45}

el servidor en cambio enviaría de vuelta:

valueOfCallbackHere({"name": "John", "age": 45})

Por lo tanto, una aplicación JS del lado del cliente podría crear una scriptetiqueta que apunte api.yoursite.com/your/endpoint?name=Johny hacer que la valueOfCallbackHerefunción (que debería definirse en el JS del lado del cliente) se llame con los datos de este otro origen ).

Sean Vieira
fuente
y ¿es mejor no usar estas técnicas en absoluto y usar JSON-JBuilder y Eager Loading en su lugar? ¿O estoy confundido y son dos cosas diferentes?
1
@ user1899082: estas técnicas son en realidad conceptos de nivel más bajo de lo que le preocupará cuando use JBuilder, por ejemplo; no hay ninguna razón por la que no pueda usar JBuilder para facilitar la serialización de sus objetos dentro de sus to_jsonmétodos: mezcla y emparejar los dos render :json => some_object_that_uses_JBuilder_to_render_its_jsones (hasta donde yo sé) lícito.
Sean Vieira
Gracias Sean, su explicación me ayudó a saber cómo renderizar json con devolución de llamada, esto resolvió uno de mis problemas.
Abhi
67

¿Que quieres saber exactamente? ActiveRecord tiene métodos que serializan registros en JSON. Por ejemplo, abra su consola de rieles e ingrese ModelName.all.to_jsony verá la salida JSON. render :jsonesencialmente llama to_jsony devuelve el resultado al navegador con los encabezados correctos. Esto es útil para las llamadas AJAX en JavaScript en las que desea devolver objetos JavaScript para usar. Además, puede utilizar la callbackopción para especificar el nombre de la devolución de llamada que le gustaría llamar a través de JSONP.

Por ejemplo, digamos que tenemos un Usermodelo que se ve así:{name: 'Max', email:' [email protected]'}

También tenemos un controlador que se ve así:

class UsersController < ApplicationController
    def show
        @user = User.find(params[:id])
        render json: @user
    end
end

Ahora, si hacemos una llamada AJAX usando jQuery así:

$.ajax({
    type: "GET",
    url: "/users/5",
    dataType: "json",
    success: function(data){
        alert(data.name) // Will alert Max
    }        
});

Como puede ver, logramos obtener el usuario con id 5 de nuestra aplicación rails y usarlo en nuestro código JavaScript porque se devolvió como un objeto JSON. La opción de devolución de llamada simplemente llama a una función de JavaScript del nombre pasado con el objeto JSON como primer y único argumento.

Para dar un ejemplo de la callbackopción, eche un vistazo a lo siguiente:

class UsersController < ApplicationController
    def show
        @user = User.find(params[:id])
        render json: @user, callback: "testFunction"
    end
end

Ahora podemos crear una solicitud JSONP de la siguiente manera:

function testFunction(data) {
    alert(data.name); // Will alert Max
};

var script = document.createElement("script");
script.src = "/users/5";

document.getElementsByTagName("head")[0].appendChild(script);

La motivación para usar una devolución de llamada de este tipo suele ser eludir las protecciones del navegador que limitan el intercambio de recursos de origen cruzado (CORS). JSONP ya no se usa mucho, sin embargo, porque existen otras técnicas para eludir CORS que son más seguras y fáciles.

Max
fuente
¿Puedes extender un poco tu ejemplo? Agregar una callback:opción en el rendermétodo y luego mostrarla dentro de la Ajaxllamada.
Arup Rakshit
15

Por el caso de

render :json => @projects, :include => :tasks

Está indicando que desea renderizar @projectscomo JSON e incluir la asociación tasksen el modelo del proyecto en los datos exportados.

Por el caso de

render :json => @projects, :callback => 'updateRecordDisplay'

Está indicando que desea renderizar @projectscomo JSON y envolver esos datos en una llamada javascript que se renderizará como:

updateRecordDisplay({'projects' => []})

Esto permite que los datos se envíen a la ventana principal y eviten problemas de falsificación entre sitios.

Kelly
fuente