在 Rails 3 中处理 JS/ERB 模板中的 JSON

Posted

技术标签:

【中文标题】在 Rails 3 中处理 JS/ERB 模板中的 JSON【英文标题】:Handling JSON in JS/ERB template in Rails 3 【发布时间】:2011-04-15 00:30:39 【问题描述】:

使用 JSON 对象和 jQuery-rails(jQuery 库加上一个特殊的 rails.js 文件)对 Rails(3) 进行典型的 AJAX 调用和从 Rails(3) 调用我没有任何问题。

不过,在一个控制器中,我想在 AJAX 调用之后在 erb 模板 (create.js.erb) 中返回一些 JSON。

我已经尝试了控制器(@object.to_json、'["content":"hello world"]' 等)和模板本身(JSON.parse()、单引号,双引号等),但对象继续呈现如下:

'["groups":,"created_at":"2010-09-21T03:49:34Z" ...

结果,我的 jQuery 代码无法解析它,我得到了错误。

我需要如何在控制器中准备我的对象,我需要在视图中使用什么 erb 语法才能将其呈现为有效的 JSON 对象?

非常感谢!

【问题讨论】:

【参考方案1】:

我不确定这是不是这个原因,但您也可以尝试使用html_safe 方法。 ERB 可能正在转义您的 JSON,因为它认为它不是 html 安全的。尝试使用字符串时调用该方法:

@object.to_json.html_safe

【讨论】:

注意:如果您将结果嵌入到脚本标签中,则在不转义的情况下调用 html_safe 可能会导致 XSS 漏洞。 查看railscast,了解如何安全使用html_safe 注意,只有在用户提供的数据(例如通过表单提交的数据)上调用 html_safe 时,在此调用 html_safe 才是危险的。如果您在后端提供的下拉列表中执行此操作,那么您就可以了。【参考方案2】:

单独使用html_escaperaw 会留下vulnerable to XSS。

相反,定义json_escape(又名j)助手的合理版本:

module ActionView::Base
  def json_escape(s)
    result = s.to_s.gsub('/', '\/')
    s.html_safe? ? result.html_safe : result
  end

  alias j json_escape
end

像这样使用它:

<script>
  var Accounts = new Backbone.Collection;
  Accounts.reset(<%=j @accounts.to_json.html_safe %>);
  var Projects = new Backbone.Collection;
  Projects.reset(<%=j @projects.to_json(:collaborators => true).html_safe %>);
</script>

更多详情请参阅this post。

请注意,ERB::Util 中的 j 别名为 json_escape 和 ActionView::Helpers::javascriptHelper 中的 j 别名为 escape_javascript 之间有一个 naming conflict。我希望 JavaScriptHelper 别名将重命名为 js

【讨论】:

这个答案应该是被接受的——互联网上有多少帖子建议使用 html_safe 而不转义,这真是令人震惊。 我认为应该是class ActionView::Base,而不是module。此外,是否有任何理由不默认设置为 html_safe ?我想不出你想要 json_escape 然后 html_escape 的任何情况。 快速提问:module ActionView::Base ... end 定义应该放在 Rails 项目的什么位置?是否有标准路径或文件? Rails 4:只需要 to_json.html_safe'&lt;script&gt;'.to_json =&gt; "\"\\u003cscript\\u003e\"" 你的意思是result.html_safe? ? result.html_safe : result【参考方案3】:

要返回json,您必须在控制器中编写渲染,如下所示:

render :json => @object

.to_json 会自动被调用。

如果您想包含一些关系,您可以执行以下操作:

render :json => @post.to_json(:include => [:comments, :authors])

我不确定使用 erb 来渲染你的 json 是否可行。

【讨论】:

【参考方案4】:

您可以在控制器中调用 render,但如果您可能需要渲染多个部分以供处理程序随后插入 dom,这将是一个问题。我需要将多个 html 片段设置为一个哈希,并且我已经能够返回 erb,它基本上使用 hash.to_json.html_safe,正如 neutrino 上面所建议的那样,并允许我在此过程中渲染多个部分。

【讨论】:

【参考方案5】:

只需要to_json.html_safe

> `'<script>'.to_json`
=> "\"\\u003cscript\\u003e\""

使to_json 响应html_safe? 并自动返回true 的补丁:

# just use .to_json instead of .to_json.html_safe
ActiveSupport::JSON.class_eval do
  class << self
    def encode_with_html_safe *args
      self.encode_without_html_safe(*args).html_safe
    end
    alias_method_chain :encode, :html_safe
  end
end

【讨论】:

以上是关于在 Rails 3 中处理 JS/ERB 模板中的 JSON的主要内容,如果未能解决你的问题,请参考以下文章

js.erb 不在 Rails 6 中渲染

Rails 6:Ajax 不接受 js.erb 中的渲染

Rails update.js.erb 不执行 javascript

在rails中使用js.erb

Bootstrap 4 和 Rails 6:$(...).modal 不是“.js.erb”文件中的函数(但适用于其他 .js 文件?)[关闭]

Rails 3 升级:使用数组作为参数从 js.erb 调用 javascript 函数