Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Render a complete page in rails 3 without controller
# 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
@redconfetti

This comment has been minimized.

Copy link

commented Oct 19, 2011

Thanks for posting this. This is exactly what I needed after I created a rake task that needed to render a partial. I only needed to add 'include Appname::Application.routes.url_helpers' inside of the OfflineTemplate to ensure that it included the URL helpers that are generated from the routes.

I did it like:

      Appname::Application.routes.default_url_options = { :host => 'www.mydomain.com' }
      template = OfflineTemplate.new
      partial_results_html = template.render_to_string(:partial=>"shared/search_results_email_html", :object => search_object, :format => :html)
@juggy

This comment has been minimized.

Copy link
Owner Author

commented Oct 20, 2011

Yes I updated the gist with my latest production version which includes the routes as you mentioned.

@mark-ellul

This comment has been minimized.

Copy link

commented Nov 24, 2011

I have tried to use this for a partial which calls a helper in the application_helper, and I get that mixed in as below... but now it cannot find the host_with_port...

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 ActionDispatch::Routing::UrlFor
  #include ActionController::PolymorphicRoutes
  include ActionView::Helpers
  include ApplicationHelper

  include Rails.application.routes.url_helpers
  # this is you normal rails application helper
  #helper.extend 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
    FakeRequest.new
  end

  def default_url_options
    {:host=>"itest.me"}
  end


end




class SiteUserRenderer < OfflineTemplate
  attr_accessor :current_site, :current_user

end
@juggy

This comment has been minimized.

Copy link
Owner Author

commented Nov 25, 2011

I am pretty sure default_url_options does not go there.

You can try as redconfetti did:

Appname::Application.routes.default_url_options = { :host => 'www.mydomain.com' }
@mark-ellul

This comment has been minimized.

Copy link

commented Nov 25, 2011

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

@mcspring

This comment has been minimized.

Copy link

commented Sep 22, 2013

Hi,

I use this code. But I cannot access root_url and asset_* helpers.

@maletor

This comment has been minimized.

Copy link

commented Jan 25, 2014

This..... or Tilt.

@michael-wheelock

This comment has been minimized.

Copy link

commented Apr 14, 2014

This is exactly what I was looking for to render a long running report from a background job. Thank you, Juggy!

@paulleader

This comment has been minimized.

Copy link

commented Apr 24, 2014

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.

@rafaelcgo

This comment has been minimized.

Copy link

commented Sep 23, 2014

Almost done. Can't make urls or assets work...
undefined method 'host' for nil:NilClass

@mcspring, Did you find a way to fix it?

@rafaelcgo

This comment has been minimized.

Copy link

commented Sep 23, 2014

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' }
@rafaelcgo

This comment has been minimized.

Copy link

commented Sep 23, 2014

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
@marckohlbrugge

This comment has been minimized.

Copy link

commented Oct 11, 2014

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
@anthonylebrun

This comment has been minimized.

Copy link

commented Feb 7, 2017

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.

@chrise86

This comment has been minimized.

Copy link

commented Mar 2, 2018

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.