Easy Printable Pages with Rails
March 5th, 2007
Print-friendly pages require either code forking or magic tricks with CSS, right? Not with Rails. You barely have to modify your code to make this work. You will need to be using Rails’ web service support with respond_to blocks.
Fun part first. Just add a line to your respond_to block, like this:
1 2 3 4 |
respond_to do |format| format.html format.print { render :layout => "print" } end |
Next, you’ll need a layout for your print-friendly page. Create a new layout called print.rhtml, and create the associated print stylesheet(s). I’ll wait while you do that.
Now you’ll need to add a mime type for the print format. You can register a new mime type with your server. But a quicker way to do this is to add this line to your environment.rb file:
Mime::Type.register "text/html", :print |
Make sure to restart your application so that the mime type is actually loaded.
Now the money shot – add a link to your new print-friendly page:
<%= link_to "Print this", {:format => "print"} %> |
That’s it! No code forking, nothing too hard, and easy to maintain. And to top it all off, you get neat looking URLs like www.example.com/pages/123.print.
March 6th, 2007 at 09:47 AM
Ryan, can I ask another somewhat related question in an effort to better understand Ruby.
in the call to the respond_to method, is the code block from do to end being passed in to the respond_to method as an argument? it looks like it is from the definition of the respond_to method, but I’m not quite sure.
and if so, it looks like the format.print line and the like are defining methods on the format variable, which is actually an instance of the Responder class. one of which is executed in the respond method based on the mime type (or :format) in the params hash.
does that sound right?
March 7th, 2007 at 10:38 AM
For others who want to follow along, Dan has been reading the
mime_responds.rbfile, which on my system can be found in/usr/local/lib/ruby/gems/1.8/gems/actionpack-1.13.1/lib/action_controller/mime_responds.rb.I’m a little hazy on the details of what’s going on here, but I think you’re essentially right.
Here’s the
respond_tomethod in full:@def respond_to(*types, &block) raise ArgumentError, "respond_to takes either types or a block, never both" unless types.any? ^ block block ||= lambda { |responder| types.each { |type| responder.send(type) } } responder = Responder.new(block.binding) block.call(responder) responder.respond end@So
formatgets passed in as*types, followed by the block. If no block is defined, then it iterates over each type (in our example, the types arehtmlandprint), essentially building a block with default values. (Somebody correct me if this is wrong.)Then it creates a new instance of the Responder class, which looks up the binding in the list of MIME types.
What happens next is where it gets hazy. I think that
method_missingcomes into play inblock.call(responder). I think that this just sends the responder as a method to the block, which catches it with method_missing. It’s not clear to me why this works on the block object. It’s also not clear to me how the block selects the correct mime type based on the block given.If anybody else can share some insight into how the responds_to method works, it would be greatly appreciated!
March 7th, 2007 at 03:08 PM
thanks for the response Ryan. those few things were hazy to me as well. I know it’s not the most important thing in the world to understand everything that goes on in Rails, but it’s at least interesting to me :)
March 7th, 2007 at 09:28 PM
Thanks for sharing this snippet of code. I haven’t advanced enough in building my first Rails app yet to worry about Print-friendly pages (not that it looks like it’ll be complicated based on your post), but when I do this will be the perfect resource. Thanks again for sharing your knowledge with the rest of us.