在Rails 4中渲染rake任务/后台作业/模型中的部分/视图

Tho*_*emm 24 ruby ruby-on-rails ruby-on-rails-4

我已经阅读了很多关于在rake任务/后台作业/模型中渲染Rails部分和视图的内容.我在Stackoverflow和Web上发现的绝大多数事情描述了在Rails 3中工作的方法,但它们似乎过时了,我没有让它们工作(即使花了很多时间进行实验).

那么,如何在Rails 4中渲染后台作业中的部分?

这是迄今为止我已经研究过的最好的方法(在控制台中演示).

c = ApplicationController.new
result = c.render_to_string(partial: 'tweets/tweet', locals: {tweet: Tweet.first})
# =>
#   Tweet Load (0.8ms)  SELECT "tweets".* FROM "tweets" ORDER BY "tweets"."id" ASC LIMIT 1
#   Author Load (0.6ms)  SELECT "authors".* FROM "authors" WHERE "authors"."id" = $1 ORDER BY "authors"."id" ASC LIMIT 1  [["id", 1]]
#   Status Load (0.6ms)  SELECT "statuses".* FROM "statuses" WHERE "statuses"."twitter_id" = 367523226848866304 LIMIT 1
#   Rendered tweets/_tweet_body.html.slim (17.5ms)
#   Rendered tweets/_resolved_tweet.html.slim (23.7ms)
#   Rendered tweets/_tweet.html.slim (28.1ms)
# ActionView::Template::Error: undefined method `tweet_path' for #<#<Class:0x007fb21bf797a0>:0x007fb21cb009e8>
# from /Users/thomasklemm/.rbenv/versions/2.0.0-p195/lib/ruby/gems/2.0.0/gems/actionpack-4.0.0/lib/action_dispatch/routing/polymorphic_routes.rb:129:in `polymorphic_url'
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?提前致谢!

更新:tweet_path上面提到的确实没有定义.= link_to 'Tweet', [@project, tweet]使用实例变量链接到路径(slim模板)导致此错误,该实例变量将存在于从某个控制器继承的视图中,但在此上下文之外呈现时则不会.我通过适当的关联解决了这个问题= link_to 'Tweet', [tweet.project, tweet].

Tho*_*emm 38

这是我从许多来源编译的内容以及在Rails 4中对我有用的内容.

使用此Renderer类,您应该能够在任何上下文中呈现Rails 4视图和部分视图,例如后台作业,服务对象,模型,工作者,您可以为其命名.

# app/services/renderer.rb
# Render views and partials in rake tasks,
# background workers, service objects and more
#
# Use:
#
# class MyService
#   def render_stuff
#     result = renderer.render(partial: 'tweets/tweet', locals: {tweet: Tweet.first})
#     # or even
#     result = renderer.render(Tweet.first)
#   end
#
#   private
#
#   def renderer
#     @renderer ||= Renderer.new.renderer
#   end
# end
#
class Renderer
  def renderer
    controller = ApplicationController.new
    controller.request = ActionDispatch::TestRequest.new
    ViewRenderer.new(Rails.root.join('app', 'views'), {}, controller)
  end
end

# app/services/view_renderer.rb
# A helper class for Renderer
class ViewRenderer < ActionView::Base
  include Rails.application.routes.url_helpers
  include ApplicationHelper

  def default_url_options
     {host: Rails.application.routes.default_url_options[:host]}
  end
end
Run Code Online (Sandbox Code Playgroud)

更新:

似乎有一个更简单的解决方案:http://makandracards.com/makandra/17751-render-a-view-from-a-model-in-rails

ApplicationController.new.render_to_string(
  :template => 'users/index',
  :locals => { :@users => @users }
)
# Mind the weird syntax to set @ variables in :locals.
Run Code Online (Sandbox Code Playgroud)

更新2:

有一个叫做的宝石render_anywhere允许从任何地方调用"渲染":模型,后台作业,rake任务等.

更新3:

Rails 5中,渲染器已被解压缩,可以从后台作业和其他地方独立使用:

ApplicationController.renderer.render(
  partial: 'messages/message',
  locals: { message: message }
)
Run Code Online (Sandbox Code Playgroud)

对于Rails <= 4.2,可以使用backport_new_renderer gem向后移植此功能.

  • 感谢更新3![backport_new_renderer](https://github.com/brainopia/backport_new_renderer)gem运行良好,并提供最简单的Rails 5更新选项. (3认同)
  • @JeremyBurton你是否包括资产助手(js,css,public)?你能给出一个代码示例吗? (2认同)