-
-
Save juggy/977181 to your computer and use it in GitHub Desktop.
# create the template | |
template = PageOfflineTemplate.new | |
template.quote = quote | |
template.pages = quote.build_pages | |
# Here I render a template with layout to a string then a PDF | |
pdf = PDFKit.new template.render_to_string(:template=>"quotes/review.html.haml") | |
class OfflineTemplate < AbstractController::Base | |
# Include all the concerns we need to make this work | |
include AbstractController::Logger | |
include AbstractController::Rendering | |
include AbstractController::Layouts | |
include AbstractController::Helpers | |
include AbstractController::Translation | |
include AbstractController::AssetPaths | |
include ActionController::UrlFor | |
include Rails.application.routes.url_helpers | |
# this is you normal rails application helper | |
helper ApplicationHelper | |
# Define additional helpers, this one is for csrf_meta_tag | |
helper_method :protect_against_forgery? | |
# override the layout in your subclass if needed. | |
layout 'application' | |
# configure the different paths correctly | |
def initialize(*args) | |
super() | |
lookup_context.view_paths = Rails.root.join('app', 'views') | |
config.javascripts_dir = Rails.root.join('public', 'javascripts') | |
config.stylesheets_dir = Rails.root.join('public', 'stylesheets') | |
config.assets_dir = Rails.root.join('public') | |
end | |
# we are not in a browser, no need for this | |
def protect_against_forgery? | |
false | |
end | |
# so that your flash calls still work | |
def flash | |
{} | |
end | |
def params | |
{} | |
end | |
# same asset host as the controllers | |
self.asset_host = ActionController::Base.asset_host | |
# and nil request to differentiate between live and offline | |
def request | |
nil | |
end | |
end |
# subclass to define the @ attributes your tempalte will use | |
class PageOfflineTemplate < OfflineTemplate | |
attr_accessor :pages, :quote, :invoice, :quotes, :mat_pages, :wo_pages, :exp_pages | |
end |
Hi,
I had tried that. Though I found this bug report on the web https://rails.lighthouseapp.com/projects/8994/tickets/6652
I am not sure if this has been fixed or even acknowledged.
I will try and create a test project to show this failure. If you know how to get around this issue some other way... Would really appreciate any help
Hi,
I use this code. But I cannot access root_url
and asset_*
helpers.
This..... or Tilt.
This is exactly what I was looking for to render a long running report from a background job. Thank you, Juggy!
Thanks so much for this. I've been going a bit loopy trying to geneterate PDFs with PDFKit that I could then attack to emails, this works a treat.
Almost done. Can't make urls or assets work...
undefined method 'host' for nil:NilClass
@mcspring, Did you find a way to fix it?
I have a fix to make url_for
helper work again without a valid request (offline on a rake task or resque task)
Make these changes to @juggy gist:
- remove
request
method - remove
include ActionController::UrlFor
(needs a request object) - add
include ActionDispatch::Routing::UrlFor
(doesnt, and can make urls with url_for properly.) - add
Rails.application.routes.default_url_options = { :host => 'www.yoursite.com' }
class OfflineTemplate < AbstractController::Base
include AbstractController::Logger
include AbstractController::Rendering
include AbstractController::Layouts
include AbstractController::Helpers
include AbstractController::Translation
include AbstractController::AssetPaths
include ActionDispatch::Routing::UrlFor
include Rails.application.routes.url_helpers
Rails.application.routes.default_url_options = { :host => 'www.yoursite.com' }
helper ApplicationHelper
helper_method :protect_against_forgery?
# configure the different paths correctly
def initialize(*args)
super()
lookup_context.view_paths = Rails.root.join('app', 'views')
config.javascripts_dir = Rails.root.join('public', 'javascripts')
config.stylesheets_dir = Rails.root.join('public', 'stylesheets')
config.assets_dir = Rails.root.join('public')
end
# we are not in a browser, no need for this
def protect_against_forgery?
false
end
# so that your flash calls still work
def flash
{}
end
def params
{}
end
# same asset host as the controllers
self.asset_host = ActionController::Base.asset_host
end
FWIW, if you've already set config.action_mailer.default_url_options
you can use the following in OfflineTemplate
to keep it DRY:
Rails.application.routes.default_url_options = Rails.application.config.action_mailer.default_url_options
Blimey. I think Joe Armstrong nailed it when he said:
I think the lack of reusability comes in object-oriented languages, not functional languages. Because the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.
If you have referentially transparent code, if you have pure functions — all the data comes in its input arguments and everything goes out and leave no state behind — it’s incredibly reusable.
Had to do this for Rails 5.0.6:
class OfflineTemplate < AbstractController::Base
include AbstractController::Logger
include AbstractController::Rendering
include ActionView::Layouts
include AbstractController::Helpers
include AbstractController::Translation
include AbstractController::AssetPaths
include ActionDispatch::Routing::UrlFor
include Rails.application.routes.url_helpers
Rails.application.routes.default_url_options = Rails.application.config.action_mailer.default_url_options
helper ApplicationHelper
helper_method :protect_against_forgery?
# configure the different paths correctly
def initialize(*_args)
super
lookup_context.view_paths = Rails.root.join('app', 'views')
config.javascripts_dir = Rails.root.join('public', 'javascripts')
config.stylesheets_dir = Rails.root.join('public', 'stylesheets')
config.assets_dir = Rails.root.join('public')
end
# we are not in a browser, no need for this
def protect_against_forgery?
false
end
# so that your flash calls still work
def flash
{}
end
def params
{}
end
def controller_name
'offline'
end
# same asset host as the controllers
self.asset_host = ActionController::Base.asset_host
end
I am pretty sure default_url_options does not go there.
You can try as redconfetti did: