【问题标题】:How to render erb template to string inside action?如何将 erb 模板渲染为内部动作字符串?
【发布时间】:2012-12-30 07:36:59
【问题描述】:

我需要一串 html(类似于 "<html><body>Hello World</body></html>")用于传真目的。

我将它写入一个单独的 erb 文件:views/orders/_fax.html.erb, 并尝试渲染 erb:html_data = render(:partial => 'fax')

这是引发问题的控制器的一部分:

  respond_to do |format|
      if @order.save   
        html_data = render(:partial => 'fax')
        response = fax_machine.send_fax(html_data)
        ......

        format.html { redirect_to @order, notice: 'Order was successfully created.' }
        format.json { render json: @order, status: :created, location: @order }
      else  
        format.html { render action: "new" }
        format.json { render json: @order.errors, status: :unprocessable_entity }
      end
    end

它给了我一个 AbstractController::DoubleRenderError 如下:

AbstractController::DoubleRenderError in OrdersController#create

Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".

如何解决这个问题?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3


    【解决方案1】:

    原因是您不能在同一操作内多次渲染或重定向。

    但在您的代码中,您同时拥有renderredirect。我认为在你的控制器中你可以只使用渲染,假设你不需要任何 json 输出。

    试试这个

    def create
      @order.save   
      render(:partial => 'fax')
    end
    

    我没有对此进行测试,但我想你明白了:),并考虑一种处理错误的方法(以防订单未保存)。

    【讨论】:

    • 感谢您的重播。对不起,我有点误导,我已经修改了帖子。实际上“html_data = render(:partial => 'fax')”不是为了视图,它是用于传真的html模板。
    • np,所以这可能会对您有所帮助,渲染 :text => "#anything",并且为了保持代码清晰,您可以通过某种方法生成 HTML 并调用Ex:render => html_created :),所以你根本不需要erb
    【解决方案2】:

    使用#render_to_string 方法

    它的工作方式与典型的渲染方法相同,但在您需要向 json 响应添加一些模板化 HTML 时很有用

    http://apidock.com/rails/ActionController/Base/render_to_string

    【讨论】:

    • 这是一个更好、更清洁的解决方案,无需任何额外设置!
    【解决方案3】:

    如果您只需要呈现的 HTML,并且不需要控制器的任何功能,您可以尝试直接在辅助类中使用 ERB,例如:

    module FaxHelper
    
      def to_fax
        html = File.open(path_to_template).read
        template = ERB.new(html)
        template.result
      end
    
    end
    

    ERB docs 对此进行了更详细的解释。

    编辑

    要从控制器中获取实例变量,请将绑定传递给result 调用,例如:

    # controller
    to_fax(binding)
    
    # helper class
    def to_fax(controller_binding)
      html = File.open(path_to_template).read
      template = ERB.new(html)
      template.result(controller_binding)
    end
    

    注意:我从来没有这样做过,但它似乎可行:)

    【讨论】:

    • HTML 字符串中包含一些变量。它似乎必须留在控制器中并从动作中获取实例变量。有什么出路吗?
    • 对了,为什么要把to_fax方法放在helper类里呢?如果我没记错的话,辅助方法只在视图中可用。
    • 也许这不是名字的最佳选择:)。您可以随意调用它,并将其包含在控制器中,或者更好地包含在模型中。
    【解决方案4】:

    如果你不想转义 html,只需调用 .html_safe 就可以了:

    "<html><body>Hello World</body></html>".html_safe

    您的错误,请发布您的 OrdersController - 看起来您在创建操作中不止一次调用渲染或重定向。

    (顺便说一句,以防万一你尝试它 - 你不能在控制器中渲染部分 - 你只能在视图中渲染部分)

    编辑:是的,您的问题是您尝试在控制器操作中呈现部分内容。您可以使用after_create 回调来设置和发送传真——尽管您也不想使用部分(因为它们用于视图)。 http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

    编辑:对于您的传真问题,您可以创建一个普通的 Ruby 类,请参阅 Yehuda 的这个极好的建议:https://stackoverflow.com/a/1071510/468009

    【讨论】:

    • 感谢您的回复。我已将控制器添加到我的帖子中。我认为这是由erb渲染造成的。
    • 这个应用程序向餐厅发送订单,他们很难查看电子邮件,所以传真...感谢您对 after_create 回调的建议。
    • html 的字符串很长,包括变量。我希望我能把它写到一个单独的 erb 文件中......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-17
    • 2014-01-10
    • 2012-06-21
    • 2012-06-03
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    相关资源
    最近更新 更多