Sending a file *and* rendering a page

Anyone know how to send a file/data to the user agent (download it) using #send_file or #send_data, *and* render a new page in the same action?

Render the page and at the top of the page put something like this:

<meta http-equiv="REFRESH" content="1; URL=/route/to/downloadable">

Just make sure that gets into your page before the closing </head>.

-philip

Philip Hallstrom wrote:

Anyone know how to send a file/data to the user agent (download it) using #send_file or #send_data, *and* render a new page in the same action?

Render the page and at the top of the page put something like this:

<meta http-equiv="REFRESH" content="1; URL=/route/to/downloadable">

Just make sure that gets into your page before the closing </head>.

-philip

Thanks! That works fine. Not exactly elegant or very Rails-like, but it works!

I'm still open to other ideas, but at least this gets me going again.

Anyone know if there's a (real) reason why you can't send a file/data and render a page using the common Rails methods? (Besides the fact that someone early on forgot about this possibility when creating the code that checks for a double-render...)

Because HTTP is a stateless request/response protocol. One request. One response. You're trying to respond with two things :slight_smile:

You could wrap this up in a helper/plugin to hide what's going on, but this is still going to be the end result :slight_smile:

-philip

Philip Hallstrom <rails@...> writes:

> Anyone know how to send a file/data to the user agent (download it) > using #send_file or #send_data, *and* render a new page in the same > action?

Render the page and at the top of the page put something like this:

<meta http-equiv="REFRESH" content="1; URL=/route/to/downloadable">

Meta http-equiv tags are a bit redundant in a web application where you can set the headers yourself (hint: http-equiv = 'equivalent to an HTTP header')

http-equiv was designed for environments where authors didn't have access to changing the headers (i.e. uploading a static HTML page), and was a nasty hack even back then. Sending the correect header is definitely nicer.

Because HTTP is a stateless request/response protocol. One request. One response. You're trying to respond with two things :slight_smile:

You could wrap this up in a helper/plugin to hide what's going on, but this is still going to be the end result :slight_smile:

-philip

Yeah. Oh well.

Since I've really got data that I want to send (rather than a file), and I don't want to create a temporary file from it, I instead put it into the flash. The new URL in the META tag is a controller action that pulls the data out of flash.now and uses #send_data to create the response. Works well, except for the ugliness of putting that meta tag in the layout for this view only...

Change your layout to include this at the top (in the <head> tag):

   <%= yield "page_header" %>

Then in your view do this:

<% content_for("page_header") do -%> <meta http-equiv="REFRESH" content="3; URL=urlgoeshere"> <% end -%>

That's what we do. And you'll find other uses for it too... like having a yield block for javascript that *has* to go at the bottom of the page just before the closing </body> because IE can't deal with it in the middle, etc...

-philip

Anyone know how to send a file/data to the user agent (download it) using #send_file or #send_data, *and* render a new page in the same action?

Render the page and at the top of the page put something like this:

<meta http-equiv="REFRESH" content="1; URL=/route/to/downloadable">

Meta http-equiv tags are a bit redundant in a web application where you can set the headers yourself (hint: http-equiv = 'equivalent to an HTTP header')

Good point. But if you need to cache that page then this wouldn't work...