从rake任务中使用render_to_string

11

我想使用Rake任务来缓存我的站点地图,这样对于 sitemap.xml 的请求就不会花费太长时间。以下是我目前拥有的:

  @posts = Post.all

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

但是当我尝试运行此代码时,出现了错误:

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

如何在Rake中将模板渲染为字符串?


这篇文章很有用。http://stackoverflow.com/questions/30725119/render-a-view-from-a-rake-task - se_pavel
3个回答

10

以下是我是如何做到的:

  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)

注意,我将我的模板转换为部分模板以使其起作用。


你在哪里使用default_url_options哈希? - se_pavel

4

有一篇关于如何从rake任务访问ActionView :: Base方法和上下文的文章

然而,这是一个猴子补丁。为什么不使用Rails的缓存机制来实现缓存呢? :)

后来编辑: render_to_string函数在ActionController :: Base上下文中定义。

以下是如何从rake任务中使其工作的解决方案,取自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}
  )
)

缓存机制很好,但有时您确实只想定期将内容离线生成到文件中。Rake任务是这样做的完美场所 - 好链接。 - Jonathan Julian
我无法使用缓存,因为我不能在HTTP请求的响应中仅呈现一次站点地图,因为它需要超过30秒,而Heroku会在30秒内超时HTTP请求。 - Tom Lehman
你说得有道理。那么,从粘贴的链接中提出的方法对你有效吗? - Vlad Zloteanu
实际上这并不起作用 - 我得到了错误信息“undefined method 'render_to_string' for #ActionView::Base:0x101db8808”(请注意,我正在使用render_to_string:template => whatever,而帖子作者正在使用render:partial => whatever)。我想将我的模板转换为部分文件,但它是一个.builder,我认为它不能作为部分文件工作?有什么想法吗? - Tom Lehman
1
实际上,当我将.builder设置为部分时,它确实可以工作。现在,当我尝试调用x_url(例如post_url)时,我遇到了一个新的错误。如何访问生成URL的帮助程序? - Tom Lehman
1
+Horace Loeb:你解决了生成URL的辅助工具的访问问题了吗? - Mark Ellul

1

最近我想把一个像Horace Loeb提到的rake任务转换成一个自包含的后台作业,但是它并不容易转换。

这是我为Rails 2.3.x实现的代码,因为我找到的Rails 3实现不能工作。

# Public: Template to render views outside the context of a controller.
#
# Useful for rendering views in rake tasks or background jobs when a
# controller is unavailable.
#
# Examples
#
#   template = OfflineTemplate.new(:users)
#   template.render("users/index", :layout => false, :locals => { :users => users })
#
#   template = OfflineTemplate.new(ProjectsHelper, PermissionsHelper)
#   template.render("projects/recent", :projects => recent_projects)
#
class OfflineTemplate
  include ActionController::UrlWriter
  include ActionController::Helpers::ClassMethods

  # Public: Returns the ActionView::Base internal view.
  attr_reader :view

  # Public: Convenience method  to
  delegate :render, :to => :view

  # Public: Initialize an offline template for the current Rails environment.
  #
  # helpers - The Rails helpers to include (listed as symbols or modules).
  def initialize(*helpers)
    helper(helpers + [ApplicationHelper])
    @view = ActionView::Base.new(Rails.configuration.view_path, {}, self)
    @view.class.send(:include, master_helper_module)
  end

  private

  # Internal: Required to use ActionConroller::Helpers.
  #
  # Returns a Module to collect helper methods.
  def master_helper_module
    @master_helper_module ||= Module.new
  end
end

此代码可在Gist中获得: https://gist.github.com/1386052

随后,您可以使用上述类创建一个OfflineTemplate来在Rake任务中呈现您的视图:

task :recent_projects => :environment do 
  template = OfflineTemplate.new(ProjectsHelper, PermissionsHelper)
  puts template.render("projects/recent", :projects => recent_projects)
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接