在 Rails 4 中渲染部分/在 rake 任务/后台作业/模型中查看 [英] Rendering partials / view in a rake task / background job / model in Rails 4
问题描述
我已经阅读了很多关于在 rake 任务/后台作业/模型中渲染 Rails 部分和视图的内容.我在 Stackoverflow 和网络上发现的绝大多数内容都描述了在 Rails 3 中工作的方法,但它们似乎已经过时,我没有让它们工作(即使花了相当多的时间进行实验).
I've read a lot on rendering Rails partials and views in rake tasks / background jobs / models. The vast majority of things I have found on Stackoverflow and the web describe approaches working in Rails 3, but they seem outdated and I didn't get them to work (even with quite some time spent experimenting).
那么,我如何在 Rails 4 的后台作业中渲染部分内容?
这是我迄今为止制定的最佳方法(在控制台中演示).
Here's the best approach I've worked out so far (demonstrated in the console).
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'
有什么想法吗?提前致谢!
Any ideas? Thanks in advance!
更新:上面提到的tweet_path
确实没有定义.此错误是由于使用实例变量链接到路径 = link_to 'Tweet', [@project, tweet]
(超薄模板)而导致的,该实例变量将出现在从某个控制器继承的视图中,但在在此上下文之外呈现.我通过适当的关联解决了这个问题,而不是 = link_to 'Tweet', [tweet.project, tweet]
.
Update: The tweet_path
mentioned above is indeed not defined. This error resulted from linking to a path = link_to 'Tweet', [@project, tweet]
(slim templates) using an instance variable that would be present in views inheriting from a certain controller, but not when rendered outside of this context. I solved this going through the appropriate association instead = link_to 'Tweet', [tweet.project, tweet]
.
推荐答案
以下是我从大量来源编译的内容,以及在 Rails 4 中对我有用的内容.
Here's what I compiled from lots of sources and what works for me in Rails 4.
使用这个 Renderer 类,您应该能够在任何上下文中渲染 Rails 4 视图和部分,例如后台作业、服务对象、模型、工作人员,等等.
With this Renderer class, you should be able to render Rails 4 views and partials in any context, like background jobs, service objects, models, workers, you name it.
# 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
更新:
似乎有一个更简单的解决方案:http://makandracards.com/makandra/17751-render-a-view-from-a-model-in-rails
There seems to be an easier solution: 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.
更新 2:
有一个名为 render_anywhere
的 gem,它允许从任何地方:模型、后台作业、rake 任务等.
There's a gem called render_anywhere
that allows for calling "render" from anywhere: models, background jobs, rake tasks, etc.
更新 3:
在 Rails 5 中,渲染器已经被提取出来,可以从后台作业和其他地方独立使用:
In Rails 5, the renderer has been extracted and can be used standalone from background jobs and other places:
ApplicationController.renderer.render(
partial: 'messages/message',
locals: { message: message }
)
对于 Rails <= 4.2,可以使用 backport_new_renderer gem 向后移植此功能.
For Rails <= 4.2, this functionality can be backported with the backport_new_renderer gem.
这篇关于在 Rails 4 中渲染部分/在 rake 任务/后台作业/模型中查看的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!