如何将JBuilder视图的JSON表示呈现为字符串?

25
我正在使用JBuilder来返回一些JSON数据。我有一个index.json.jbuilder文件用于生成数据,现在我需要将其渲染成字符串。但是,由于@my_object.to_json@my_object.as_json似乎不能通过JBuilder来实现,所以我不确定该如何操作。
那么如何将JBuilder视图渲染为字符串呢?

你是想从控制器返回JSON响应,还是独立构建一个JSON字符串? - Winfield
8个回答

45

我正在控制器中将用户集合渲染为一个JSON字符串,代码如下:

#controllers/users_controller.rb
def index
  @users = User.all
  @users_json = render_to_string( template: 'users.json.jbuilder', locals: { users: @users})
end

#views/users/users.json.jbuilder
json.array!(users) do |json, user|
  json.(user, :id, :name)
end

嗨,亚伦,我尝试实现上述技术,但当我转到该页面时,我收到一个缺少模板错误:“缺少模板/work.json,其中 {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :arb, :jbuilder, :coffee]}。”我对rails有点陌生,不太确定发生了什么。任何帮助将不胜感激。先在这里谢谢! - jordancooperman
我的控制器中使用“respond_to :json”仍然出现相同的错误。 - jordancooperman
3
答案对我没用。render_to_string 改变了响应的内容类型为 json(index 应该呈现为 html)。 - vrepsys
如果您在渲染模板时遇到问题,可能需要指定格式。render_to_string:template =>“template”,:formats => [:json] Rails通常从模板名称“users.json.jbuilder”推断出格式应设置为JSON。 - Aaron Renoir
如果您希望视图在生成JSON后继续呈现HTML(例如将JSON包含在HTML页面中),则需要告诉Rails切换回HTML格式。您可以在操作的末尾添加以下行:render :index, formats: [:html] - jwadsack
显示剩余4条评论

9
如果视图users.json.jbuilder在默认路径相对于控制器的位置,并且无法找到模板,可能是由于format不匹配导致的,因为它可能尝试查找html格式文件。有两种修复方法:
  1. 让客户端进行GET请求/users/index.json

    或者

  2. 在调用render_to_string(也适用于render)时指定formats选项:


#controllers/users_controller.rb
def index
  @users = User.all
  @users_json = render_to_string( formats: 'json' ) # Yes formats is plural
end

这在Rails 4.1中已经验证过了。


我认为这应该被选为解决方案,因为它适用于常见情况,并且比所选方案容易得多。 - Neil Woods
2
任何使用Rails 4.1的人都应该使用这个答案。 - Stone

5
如果您在控制器中执行此操作,更简单的选择是尝试将代码移动到控制器正在呈现的视图中。我在这里描述了这个过程:https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/docs/jbuilder.md。基本上,您可以在视图中调用render函数,然后就完成了。
<%= react_component('App', render(template: "/comments/index.json.jbuilder"),
    generator_function: true, prerender: true) %>

以下是有关将数据从控制器传递到视图的说明:

class PagesController < ApplicationController
  def index
    @comments = Comment.all

    # NOTE: The below notes apply if you want to set the value of the props in the controller, as
    # compared to he view. However, it's more convenient to use Jbuilder from the view. See
    # app/views/pages/index.html.erb:20
    #
    #  <%= react_component('App', render(template: "/comments/index.json.jbuilder"),
    #     generator_function: true, prerender: true) %>
    #
    #
    # NOTE: this could be an alternate syntax if you wanted to pass comments as a variable to a partial
    # @comments_json_sting = render_to_string(partial: "/comments/comments.json.jbuilder",
    #                                         locals: { comments: Comment.all }, format: :json)
    # NOTE: @comments is used by the render_to_string call
    # @comments_json_string = render_to_string("/comments/index.json.jbuilder")
    # NOTE: It's CRITICAL to call respond_to after calling render_to_string, or else Rails will
    # not render the HTML version of the index page properly. (not a problem if you do this in the view)
    # respond_to do |format|
    #   format.html
    # end
  end
end

3
你也可以像这样做,这样可以让你的控制器更加简洁。
# controller
def new
  @data = Data.all
end


# view
<% content_for :head do %>
  <script type="text/javascript">
    var mydata = <%= raw render :partial => 'path/to/partial', :locals => {data: @data} %>;
  </script>
<% end %>


# path/to/_partial.html.jbuilder
json.array!(@data) do |d|
  json.extract! field1, :field2, :field3, :field4
  json.url data_url(d, format: :json)
end


# layouts/application.html
<!DOCTYPE html>
<html>
<head>
  <%= yield :head %>
</head>
<body>
...
</body>
</html>

我更喜欢这种方法,而且你可以通过从扩展名中删除格式部分来使其格式无关,例如 _partial.jbuilder 可以在 json 和 html 视图中使用。 - wik
这种方法很好,但在content_tag的数据属性中无法使用。怎么回事? - maletor

2

查看源代码,似乎您可以执行以下操作:

json_string = Jbuilder.encode do |json|
  json.partial! 'path/to/index', @my_object
end

我在shell里尝试了大约20分钟,但运气不太好。如果可以的话,您能否发布一个可行的示例? - Geo
我从 Jbuilder 文档的示例中提取了这段代码片段:https://github.com/rails/jbuilder看起来嵌入式模板可能在 Ruby 1.8 下失效,只能在 Ruby 1.9 及以上版本中使用。 - Winfield
json.partial! 'path/to/index', my_object: @my_object这是正确的语法。 - maksfromspb
json = JbuilderTemplate.new(view_context) do |json| json.partial! 'filename' end.attributes!请注意,您需要使用“_filename”,因为它调用了部分渲染器。 - kuboon

2

1
在控制器中,你可以这样做:
def index
  json = JbuilderTemplate.new(view_context) do |json|
    json.partial! 'index'
  end.attributes!
  do_something(json)
  render json: json
end

请注意,您需要使用“_index.json.jbuilder”文件,因为它调用了部分渲染器。

0

跟随 justingordon 的提示。

如果您正在使用 React 组件,可以执行以下操作。

在您的控制器中:

@users = User.all

在您看来:

<%= react_component("YourComponentName",
                    props: render('your_template.json.jbuilder')) %>

这是在Rails 5.1上测试过的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接