How can I setup a user-defined template in prawn - prawnto? - ruby-on-rails

I'm using prawn with prawnto in a rails 3 application to generate some pdf's. I have created a pdf.prawn template for a specific controller's action, and it is working fine.
I have the following code in my 'document' controller, as suggested by prawnto documentation:
respond_with(#document) do |format|
format.html
format.pdf { render :layout => false } # Add this line
end
What I would like to achieve is to allow each user of the app to select different templates, and accordingly, be able to render the corresponding XXXX.pdf,prawn templates.
How can I define dynamically the prawn template name to be rendered, based on a variable, instead of the default show.pdf.prawn template?
I have been looking for a couple of days for this feature, but have
not found anything similar.
I am willing to drop prawnto and use plain prawn if this could solve this issue.
Thank you very much for your time!
Alex

I guess you can use,
render :template => "path/to/xxx.pdf.prawn", :layout => false

Related

Why does Rails render RJS templates within a layout?

I need to do this for a controller which uses the active_scaffold gem. We have a controller that looked something like this:
class Admin::UsersController < ApplicationController
layout 'admin'
active_scaffold :users do |config|
config.search.columns = [:first_name, :last_name]
end
end
That worked great when we were on Rails 2.3.10, but we're upgrading to Rails 3.0.10. As part of the upgrade, I had to upgrade active_scaffold (currently installed from the rails-3.0 branch of git://github.com/activescaffold/active_scaffold) to be compatible. One problem we were having is that searching the table wasn't working. I would see in my log files:
Rendered <snip>/gems/active_scaffold-25b3d724f35b/frontends/default/views/list.js.rjs within layouts/admin (923.5ms)
Notice that it's rendering the RJS template with the layout specified in the controller. That seems like an unreasonable default to me. Shouldn't RJS templates render without a layout by default? Anyway, I fixed it as such:
class Admin::UsersController < ApplicationController
layout :admin_layout
private
def admin_layout
respond_to do |format|
format.js { false }
format.html { 'admin' }
end
end
end
That fixes the issues with search and pagination. (The RJS template is now rendered without a layout, so the browser can execute the resulting Javascript). I guess my question is, why do I have to tell Rails that it shouldn't render RJS templates with layouts? And is there a better solution? This feels like too much of a hack to me (the bad kind of hack---the kind of hack that will break in the future).
Okay, I figured it out. #numbers1311407's comment under my question led me to check the name of the layout template. It was layouts/admin.haml. With Rails 2, that layout was only rendering for HTML requests, but with Rails 3 it applies to all requests (because it doesn't specify a format type). I renamed it to layouts/admin.html.haml and it works with a simple layout 'admin' in my controller (as opposed to the hack that I had come up with in my question).
So the answer to the question, "Why does Rails render RJS templates within a layout?" is that the layout file was named such that it applies to all formats.
Answer your quastions:
1. There is no magic that Rails renderers layout in for JS format. That's bacause it is default to Rails to render layout with any template unless you explicitly tell to avoid it. You can just look into Rails sources in file: actionpack/lib/action_controller/metal/renderers.rb to see :js renderer.
2.Try to use:
respond_to do |format|
format.js { render *your_any_options*, layout: false }
end

Rails >= 3.0.8 render inline code with layout not working

It seems the render method has changed.
In the view I used to be able to do the following:
= render :layout => 'some_layout' do
some stuff to be rendered
It seems the best fix is to move the content into a partial and call the layout
= render :partial => 'some stuff to be rendered', :layout => 'some_layout'
I was just wondering if anyone had come across this and if it is a bug or an intended change?
EDIT
Rendering a block inline with a layout works. Check out the part about applying a layout to a block within any template at http://api.rubyonrails.org/classes/ActionView/Partials.html
The issue I am having is with the latest version of HAML not rendering nested render calls properly.
https://github.com/nex3/haml/issues/412
From your post, it appears you are trying to do this in a view.
Is it possible that you are confusing ActionController's render and ActionView's render? Looking # the API documentation for 2.3.8 & 3.x, it doesn't seem there was ever a :layout option within ActionView's render.
UPDATE
Actually, I may have been off-base. It does seem that there is an :inline option as described here.
render(options = {}, locals = {}, &block)
Returns the result of a
render that’s dictated by the options hash. The primary options are:
:partial - See ActionView::Partials.
:update - Calls update_page with the block given.
:file - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
:inline - Renders an inline template similar to how it’s done in the controller.
:text - Renders the text passed in out.
This is fixed in the most recent version of HAML v3.1.3

Rails 3 rendering template missing without file ending

I have an action in my controller as below:
def show
#post = Post.find_by_setitle(params[:setitle])
if !#post
render 'error_pages/404'
return
end
respond_to do |format|
format.html
end
end
If the render error_pages/404 I get a template missing. Switching it to render error_pages/404.haml.html works fine.
Why is this?
N.B. There is no actual error_pages controller or model. Just a convenient place to keep them.
Edit: I'm using mongoid and hence don't have access to ActiveRecord. Controller base can't be looking for a particular ActiveRecord exception?
From the documentation
The render method can also use a view that’s entirely outside of your application (perhaps you’re sharing views between two Rails applications):
Rails determines that this is a file render because of the leading slash character. To be explicit, you can use the :file option (which was required on Rails 2.2 and earlier):
You need either to pass the :file option, or to start the location string with a slash. Alternatively, you could use the Rails functionality to rescue from errors, and recover from ActiveRecord::RecordNotFound with a 404. See this post for details.
You should probably use render :template => 'error_pages/404'.
I think Rails is looking for a partial called _404.
Try it out 1:
render 'error_pages/404' (and name the file _404.html.erb)
Try it out 2:
render :template => 'error_pages/404' (and name the file 404.html.erb i.e. no leading underscore)

How can you render a template within a layout using Liquid template language?

I'm trying to render a liquid template within a liquid layout (Liquid Template lang, not CSS liquid layout stuff). I can't seem to get the layout part to render. Currently using:
assigns = {'page_name' => 'test'}
#layout = Liquid::Template.parse(File.new(#theme.layout.path).read)
#template = Liquid::Template.parse(File.new(self.template.path).read)
#rend_temp = #template.render(assigns)
#rend_layout = #layout.render({'content_for_layout' => #rend_temp})
render :text => #rend_layout, :content_type => :html
The resulting HTML of the page shows that the 'template' rendered in liquid fine, but it isn't wrapped with the layout (replacing 'content_for_layout' in the layout with the rendered template)
Just to let anyone else know who comes across this problem, the code posted above actually does work, the issue is with the variable named #template. I renamed #template, and #layout to #_tempalte, and #_layout and everything works as expected.
For using liquid in ruby on rails (especially rails 3) - I believe the proper way to render your liquid templates (and also maintain all the work rails is doing for you) is as follows...
The liquid gem itself provides a liquid_view for rails so you can wire up the rails to look for "liquid" templates when you call #render. This liquid_view only works fully with rails 2.3
but can easily be updated to work with rails 3 by making the following update
if content_for_layout = #view.instance_variable_get("#content_for_layout")
assigns['content_for_layout'] = content_for_layout
elsif #view.content_for?(:layout)
assigns["content_for_layout"] = #view.content_for(:layout)
end
assigns.merge!(local_assigns.stringify_keys)
This can be seen here --> https://github.com/danshultz/liquid/commit/e27b5fcd174f4b3916a73b9866e44ac0a012b182
Then to properly render your liquid view just call
render :template => "index", :layout => "my_layout", :locals => { liquid_drop1 => drop, liquid_drop2 => drop }
In our application, since we have a handful of common liquid attributes we have overriden the "render" method in our base controller to automatically include the default locals by referencing #liquid_view_assigns which roll up additionally added liquid drops for the render call
def render(...)
options[:locals] = options.fetch(:locals, {}).merge(liquid_view_assigns)
super
end

Problems with Prawnto options

I'm using Prawnto to generate PDFs in my Rails app. I want three specific options set for my PDFs:
I don't want it to start with a blank page
I want it to download directly (not inline)
I want to specify the filename
Here's my controller method:
def print
#purchase = Purchase.find(params[:id])
prawnto :prawn=>{:skip_page_creation=>true}, :inline=>false, :filename=>#purchase.deal.name + "-" + #purchase.customer.name+".pdf"
end
Without the :skip_page_creation option, the other two options (inline and filename) work fine. But when I add the skip_page_creation option, it goes inline with a default filename. And of course, if I remove skip_page_creation, I get a nice downloaded PDF with a first blank page.
The docs for this library leave something to be desired, but can anyone point me in the right direction?
Cheers!
Aaron.
I've just tried this by changing one of my inline examples which worked ok:
module SharedPdfs
def show
prawnto :prawn => {:skip_page_creation=>true}, :inline => false, :filename => "results_pdf.pdf"
render :template => '/results/show'
end
end
Had a quick look at the prawnto source and it should pickup your prawn options not sure why it isn't but at least you've got it working for now.

Resources