【问题标题】:How could I render to a string a JSON representation of a JBuilder view?如何将 JBuilder 视图的 JSON 表示呈现为字符串?
【发布时间】:2012-04-25 14:33:49
【问题描述】:

我使用JBuilder 来返回一些 JSON。我有一个生成数据的index.json.jbuilder,我需要将它呈现为一个字符串。但是,我不确定如何执行此操作,因为:@my_object.to_json@my_object.as_json 似乎没有通过 JBuilder。

如何将 JBuilder 视图呈现为字符串?

【问题讨论】:

  • 您是想从控制器返回 JSON 作为 JSON 响应还是单独构建一个 JSON 字符串?

标签: ruby-on-rails json jbuilder


【解决方案1】:

我在控制器中将用户集合呈现为 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

【讨论】:

  • 嗨 Aaron,我尝试实现上述技术,但是当我转到该页面时,我得到一个缺少模板的错误:“缺少模板 /work.json with {:locale=>[:en] , :formats=>[:html], :handlers=>[:erb, :builder, :arb, :jbuilder, :coffee]}。”我对rails有点陌生,不太确定发生了什么。任何帮助将不胜感激。提前致谢!
  • 我猜您可能需要在控制器中添加“respond_to :json”。
  • 我的控制器中的“respond_to :json”仍然出现同样的错误
  • @arron 不确定这是否是最好的方法,但我终于让它像这样工作:“@work_json = render_to_string "work", :layout => false",并将我的 jbuilder 文件重命名为“work.html.jbuilder”。不过,您的回答肯定使我走上了正轨。 +1 谢谢!
  • 答案对我不起作用。 render_to_string 将响应的内容类型更改为json(索引应该呈现html)
【解决方案2】:

如果视图users.json.jbuilder位于相对于控制器的默认路径并且找不到模板,则可能是由于format不符,因为它可能正在尝试查找html格式文件.有两种方法可以解决此问题:

  1. 让客户端 GET /users/index.json

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


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

这已在 Rails 4.1 中得到验证。

【讨论】:

  • 我认为这应该被选为解决方案,因为它适用于常见情况并且比选择的解决方案要容易得多
  • Rails 4.1 上的任何人都应该使用这个答案。
【解决方案3】:

如果您在控制器中执行此操作,一个更简单的选择是尝试将代码移动到控制器正在呈现的视图中。

我在这里描述了这一点: 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

【讨论】:

    【解决方案4】:

    你也可以这样做,这样你的控制器会更干净一些。

    # 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 视图内部使用。
    • 这种方法很好,但它不适用于content_tag 的数据属性。什么给了?
    【解决方案5】:

    看源码,貌似可以这样:

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

    【讨论】:

    • 我在 shell 中尝试了大约 20 分钟,但运气不佳。如果问的不是太多,您能否发布一个可行的示例?
    • 我从文档中的 Jbuilder 示例中提取了这段代码 sn-p:github.com/rails/jbuilder 看起来嵌入式模板在 Ruby 1.8 下可能会损坏,并且仅适用于 Ruby 1.9 及更高版本。
    • json.partial! 'path/to/index', my_object: @my_object 这是正确的语法
    • json = JbuilderTemplate.new(view_context) 做 |json| json.partial! '文件名' end.attributes!请注意,您需要“_filename”,因为它调用部分渲染器。
    【解决方案6】:

    从控制台:

    view = ApplicationController.view_context_class.new("#{Rails.root}/app/views")
    JbuilderTemplate.encode(view){|json| json.partial!('path/to/index', @my_object) }
    

    通过https://github.com/rails/jbuilder/issues/84#issuecomment-38109709

    【讨论】:

      【解决方案7】:

      在控制器中你可以这样做

      def index
        json = JbuilderTemplate.new(view_context) do |json|
          json.partial! 'index'
        end.attributes!
        do_something(json)
        render json: json
      end
      

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

      【讨论】:

        【解决方案8】:

        按照贾斯汀戈登的建议。

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

        在您的控制器中:

        @users = User.all
        

        在你看来:

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

        这是在 Rails 5.1 上测试的。

        【讨论】:

          猜你喜欢
          • 2013-10-19
          • 2016-10-10
          • 2013-09-28
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多