14

I need a string of html (something like "<html><body>Hello World</body></html>") for faxing purpose.

I wrote it into a seprate erb file: views/orders/_fax.html.erb , and try to render the erb in action: html_data = render(:partial => 'fax').

Here is part of the controller that raises the issue:

  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

It gave me an AbstractController::DoubleRenderError as below:

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".

How to solve this problem?

Feng Wan
  • 305
  • 2
  • 3
  • 8

4 Answers4

19

If you only need the rendered HTML, and don't need any functionality from the controller, you might try using ERB directly within a helper class, eg.:

module FaxHelper

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

end

The ERB docs explain this in more detail.

EDIT

To get the instance variables from the controller, pass the binding into the result call, eg:

# 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

Note: I've never done this, but it seems workable :)

zetetic
  • 47,184
  • 10
  • 111
  • 119
  • There are some variables included in the HTML string. It seems it has to stay in the controller and takes instance variables from the action. Any way out? – Feng Wan Jan 16 '13 at 04:18
  • By the way, why do you put to_fax method in the helper class? If I remember correctly, helper methods are only available in views. – Feng Wan Jan 17 '13 at 22:42
  • Perhaps that wasn't the best choice of names :). You can call it whatever you like, and include it in the controller, or better yet in the model. – zetetic Jan 18 '13 at 00:01
8

Use the #render_to_string method

it works the same way as the typical render method but useful when you need to add some templated HTML to a json response

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

0

If you don't want to escape html, just call .html_safe on it:

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

Re your error, please post your OrdersController - looks like you are calling render or redirect more than once in the create action.

(Btw, just in case you are trying it - you can't render a partial in a controller - you can only render partials in views)

Edit: yeah your problem is you trying to render a partial in the controller action. You could use an after_create callback to set up and send the fax - though again you won't want to use a partial (as they are for views). http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

Edit: for your fax problem,you could create a normal Ruby Class, see this excellent bit of advice from Yehuda: https://stackoverflow.com/a/1071510/468009

Community
  • 1
  • 1
A4J
  • 879
  • 10
  • 24
  • Thank you for your reply. I've add the controller to my post. I think it's caused by the erb rendering thing. – Feng Wan Jan 16 '13 at 03:25
  • This app sends orders to restaurants, it's difficult for them to check emails, so fax... Thank you for your advice on the after_create callback. – Feng Wan Jan 16 '13 at 03:51
  • The string of html is pretty long, and including variables. I wish I could write it into a seperate erb file... – Feng Wan Jan 16 '13 at 03:54
0

The reason is you cannot render or redirect inside the same action more than once at a given time.

But in your code, you have both render and redirect. I think in your controller you can use simply only the render, assuming you don't need any json output.

Try this

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

I haven't tested this, but I guess you get the idea :), and think about a way to handle errors as well (in case order didn't save).

halfer
  • 19,824
  • 17
  • 99
  • 186
sameera207
  • 16,547
  • 19
  • 87
  • 152
  • Thank you for your replay. Sorry, I was a little misleading, I've revised the post. Actually "html_data = render(:partial => 'fax')" is not for the view, it's html template for fax. – Feng Wan Jan 16 '13 at 04:06
  • np, so this might help you , render :text => "#anything", and just to keep your code clear, you could generate your HTML in some method and call Ex: render => html_created :), so you dont need an erb at all – sameera207 Jan 16 '13 at 04:18