【问题标题】:Rendering JSON in controller在控制器中渲染 JSON
【发布时间】:2013-01-27 06:53:38
【问题描述】:

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

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

还有一些将 JSONP 与回调函数结合使用的示例:

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

谁能解释一下?

【问题讨论】:

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


    【解决方案1】:

    您通常会返回JSON,因为:

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

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

    或者,您可能正在吃自己的狗粮,并且两者都做

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

    为什么是:callback

    JSONP(第二个示例)是绕过Same Origin Policy 的一种方式,它是每个浏览器内置安全性的一部分。如果您的 API 位于 api.yoursite.com 并且您将从 services.yoursite.com 为您的应用程序提供服务,那么您的 JavaScript 将无法(默认情况下)从 services 向 @987654331 发出 XMLHttpRequest(XHR - aka ajax)请求@。人们一直在绕过这个限制的方式(在Cross-Origin Resource Sharing spec was finalized 之前)是通过从服务器发送 JSON 数据就好像它是 JavaScript 而不是 JSON)。因此,而不是发回:

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

    服务器会发回:

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

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

    【讨论】:

    • 完全不使用这些技术并使用 JSON-JBuilder 和 Eager Loading 会更好吗?或者我很困惑,它们是两个不同的东西。?
    • @user1899082 - 这些技术实际上是低级 概念,而不是您在使用 JBuilder 时所担心的概念,例如 - 您没有理由不这样做使用 JBuilder 在您的 to_json 方法中更轻松地序列化您的对象 - 混合和匹配这两个 render :json => some_object_that_uses_JBuilder_to_render_its_json (据我所知)是合法的。
    • 感谢 Sean,您的解释帮助我了解了如何使用回调渲染 json,这解决了我的一个问题。
    【解决方案2】:

    你到底想知道什么? 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 的技术。

    【讨论】:

    • 你能扩展一下你的例子吗?在render 方法中添加callback: 选项,然后在Ajax 调用中显示它。
    【解决方案3】:

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

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

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

    您说您希望将 @projects 呈现为 JSON,并将该数据包装在 javascript 调用中,该调用将呈现如下:

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

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

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 2017-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      • 2020-10-09
      相关资源
      最近更新 更多