Renderizando JSON no controlador

103

Eu estava lendo um livro e um capítulo sobre controladores quando ele fala sobre renderização de coisas, para JSON ele tem um exemplo como este, mas não entra em detalhes, então eu não pude entender o quadro geral em que este exemplo se encaixa:

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

E também alguns exemplos com JSONP usando-o com funções de retorno de chamada:

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

Alguém pode explicar isso?

bondade
fonte

Respostas:

127

Você normalmente vai voltar JSON porque:

A) Você está construindo parte / todo o seu aplicativo como um aplicativo de página única (SPA) e precisa do JavaScript do lado do cliente para obter dados adicionais sem recarregar totalmente a página.

ou

B) Você está construindo uma API que terceiros irão consumir e decidiu usar JSON para serializar seus dados.

Ou, possivelmente, você está comendo sua própria ração e fazendo os dois

Em ambos os casos, render :json => some_datairá JSON-ify os dados fornecidos. o:callback chave no segundo exemplo precisa de um pouco mais de explicação (veja abaixo), mas é outra variação da mesma ideia (retornar dados de uma maneira que o JavaScript possa manipular facilmente).

Por quê :callback ?

JSONP (o segundo exemplo) é uma maneira de contornar a Política de Mesma Origem que faz parte da segurança integrada de cada navegador. Se você tiver sua API em api.yoursite.come estiver servindo seu aplicativo a partir de services.yoursite.comseu JavaScript, não será (por padrão) capaz de fazer XMLHttpRequestsolicitações (XHR - também conhecidas como ajax) de servicespara api. A forma como as pessoas tentaram contornar essa limitação (antes da especificação do Compartilhamento de recursos entre origens ser finalizada ) é enviando os dados JSON do servidor como se fosse JavaScript em vez de JSON ). Assim, em vez de enviar de volta:

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

o servidor, em vez disso, enviaria de volta:

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

Assim, um aplicativo JS do lado do cliente poderia criar uma scripttag apontando para api.yoursite.com/your/endpoint?name=Johne ter a valueOfCallbackHerefunção (que teria que ser definida no JS do lado do cliente) chamada com os dados dessa outra origem .)

Sean Vieira
fonte
e é melhor não usar essas técnicas e, em vez disso, usar JSON-JBuilder e Eager Loading? Ou estou confuso e são duas coisas diferentes.?
1
@ user1899082 - essas técnicas são, na verdade , conceitos de nível inferior do que com os quais você se preocupará quando usar o JBuilder, por exemplo - não há razão para que você não possa usar o JBuilder para tornar a serialização de seus objetos mais fácil dentro de seus to_jsonmétodos - misturar e combinar os dois render :json => some_object_that_uses_JBuilder_to_render_its_jsoné (tanto quanto posso dizer) lícito.
Sean Vieira
Obrigado Sean, sua explicação me ajudou a saber sobre como renderizar json com retorno de chamada, isso resolveu um dos meus problemas.
Abhi
67

O que exatamente você quer saber? ActiveRecord tem métodos que serializam registros em JSON. Por exemplo, abra o console do Rails e entre ModelName.all.to_jsone você verá a saída JSON. render :jsonessencialmente chama to_jsone retorna o resultado ao navegador com os cabeçalhos corretos. Isso é útil para chamadas AJAX em JavaScript nas quais você deseja retornar objetos JavaScript para uso. Além disso, você pode usar ocallback opção para especificar o nome do retorno de chamada que deseja chamar via JSONP.

Por exemplo, digamos que temos um User modelo parecido com este:{name: 'Max', email:' [email protected]'}

Também temos um controlador parecido com este:

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

Agora, se fizermos uma chamada AJAX usando jQuery como este:

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

Como você pode ver, conseguimos obter o usuário com id 5 de nosso aplicativo rails e usá-lo em nosso código JavaScript porque ele foi retornado como um objeto JSON. A opção de retorno de chamada apenas chama uma função JavaScript do nome passado com o objeto JSON como o primeiro e único argumento.

Para dar um exemplo da callbackopção, dê uma olhada no seguinte:

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

Agora podemos criar uma solicitação JSONP da seguinte maneira:

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

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

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

A motivação para usar esse retorno de chamada é normalmente contornar as proteções do navegador que limitam o compartilhamento de recursos de origem cruzada (CORS). JSONP não é mais usado, entretanto, porque existem outras técnicas para contornar o CORS que são mais seguras e fáceis.

Max
fonte
Você pode estender um pouco o seu exemplo? Adicionando uma callback:opção no rendermétodo e depois exibindo-a dentro da Ajaxchamada.
Arup Rakshit de
15

Por exemplo de

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

Você está declarando que deseja renderizar @projectscomo JSON e incluir a associaçãotasks no modelo do Projeto nos dados exportados.

Por exemplo de

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

Você está declarando que deseja renderizar @projectscomo JSON e agrupar esses dados em uma chamada javascript que será renderizada de forma semelhante a:

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

Isso permite que os dados sejam enviados para a janela pai e ignorar os problemas de falsificação entre sites.

Kelly
fonte