在控制器中渲染JSON

时间:2013-02-12 02:35:58

标签: ruby-on-rails json ruby-on-rails-3.2

我正在阅读一本书和关于控制器的章节,当它讨论渲染内容时,对于JSON,它有一个这样的例子,但没有详细说明,所以我无法弄清楚这个例子的大局适合:

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

还有JSONP使用回调函数的一些例子:

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

有人可以解释这些吗?

3 个答案:

答案 0 :(得分:114)

您通常会返回JSON,因为:

A)您正在将您的部分/全部应用程序构建为单页面应用程序(SPA),并且您需要使用客户端JavaScript才能在不完全重新加载页面的情况下提取其他数据。

B)您正在构建第三方将要使用的API,并且您决定使用JSON来序列化您的数据。

或者,你可能正在吃自己的狗食并做

在这两种情况下,render :json => some_data将JSON-ify提供的数据。第二个示例中的:callback键需要更多解释(见下文),但它是同一想法的另一种变体(以JavaScript可以轻松处理的方式返回数据。)

为什么:callback

JSONP(第二个示例)是一种绕过Same Origin Policy的方法,它是每个浏览器内置安全性的一部分。如果你有你的API api.yoursite.com,您将服务应用程序关闭services.yoursite.com您的JavaScript不会(默认),能够使XMLHttpRequest(XHR - 又名AJAX)从请求servicesapi。人们一直在寻找限制(在Cross-Origin Resource Sharing spec was finalized之前)的方式是通过从服务器发送JSON数据,就像它是JavaScript而不是JSON 一样。因此,而不是发回:

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

服务器将发回:

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

因此,客户端JS应用程序可以创建一个script标记,指向api.yoursite.com/your/endpoint?name=John并具有valueOfCallbackHere函数(必须在客户端JS中定义)使用来自其他来源的数据调用。)

答案 1 :(得分:61)

你到底想知道什么? ActiveRecord具有将记录序列化为JSON的方法。例如,打开rails控制台并输入ModelName.all.to_json,您将看到JSON输出。 render :json实际上会调用to_json并使用正确的标头将结果返回给浏览器。这对于要在其中返回要使用的JavaScript对象的JavaScript中的AJAX调用很有用。此外,您可以使用callback选项指定要通过JSONP调用的回调名称。

例如,假设我们有一个User模型,如下所示:{name: 'Max', email:' m@m.com'}

我们还有一个如下控制器:

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

现在,如果我们使用jQuery进行AJAX调用:

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

正如您所看到的,我们设法从rails应用程序中获取id为5的用户并在我们的JavaScript代码中使用它,因为它是作为JSON对象返回的。回调选项只调用以JSON对象作为第一个也是唯一参数传递的命名的JavaScript函数。

要举例说明callback选项,请查看以下内容:

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

现在我们可以按如下方式创建JSONP请求:

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

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

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

使用此类回调的动机通常是绕过限制跨源资源共享(CORS)的浏览器保护。然而,JSONP不再那么用了,因为存在其他技术来绕过更安全,更容易的CORS。

答案 2 :(得分:13)

对于

的实例
render :json => @projects, :include => :tasks

您声明要将@projects呈现为JSON,并在导出数据中的项目模型中包含关联tasks

对于

的实例
render :json => @projects, :callback => 'updateRecordDisplay'

您声明要将@projects呈现为JSON,并将该数据包装在javascript调用中,该调用将呈现如下:

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

这允许将数据发送到父窗口并绕过跨站点伪造问题。