views:

305

answers:

2

I want to use a Rake task to cache my sitemap so that requests for sitemap.xml won't take forever. Here's what I have so far:

  @posts = Post.all

  sitemap = render_to_string :template => 'sitemap/sitemap', :locals => {:posts => @posts}, :layout => false
  Rails.cache.write('sitemap', sitemap)

But when I try to run this, I get an error:

undefined local variable or method `headers' for #<Object:0x100177298>

How can I render a template to a string from within Rake?

+1  A: 

There is a post about how to be able to access ActionView::Base methods and context from rake task.

However, this is a monkeypatch. Why not use the rails' cache mechanism to accomplish caching? :)

Later edit: The render_to_string function is defined in ActionController::Base context.

Below is a solution on how to make it work from rake tasks, taken from omninerd.

# In a rake task:
av = ActionView::Base.new(Rails::Configuration.new.view_path)
Rails.cache.write(
  "cache_var", 
  av.render(
    :partial => "view_folder/some_partial", 
    :locals => {:a_var => @some_var}
  )
)
Vlad Zloteanu
The cache mechanism is great, but sometimes you really just want to periodically generate the content offline into a file. A rake task is the perfect place for that - good link.
Jonathan Julian
I can't use caching because I can't render the sitemap even once in response to an HTTP request since it takes more than 30 seconds and Heroku times out HTTP requests at 30 seconds
Horace Loeb
You have a point. So, does the approach from the pasted link work for you?
Vlad Zloteanu
This actually doesn't work -- I get the error "undefined method 'render_to_string' for #<ActionView::Base:0x101db8808>" (note that I am using `render_to_string :template => whatever` and the post author is doing `render :partial => whatever`). I'd convert my template to a partial, but it's a `.builder`, which I don't think works as a partial? Any ideas?
Horace Loeb
Actually this *does* work when I make the `.builder` a partial. Now I'm getting a new error when I try to call `x_url` (e.g., `post_url`). How do I get access to the URL-generating helpers?
Horace Loeb
Updated my answer.
Vlad Zloteanu
A: 

Here's how I did it:

  av = ActionView::Base.new(Rails::Configuration.new.view_path)
  av.class_eval do
    include ApplicationHelper
  end

  include ActionController::UrlWriter
  default_url_options[:host] = 'mysite.com'

  posts = Post.all

  sitemap = av.render 'sitemap/sitemap', :posts => posts
  Rails.cache.write('sitemap', sitemap)

Note that I converted my template to a partial to make this work

Horace Loeb