2013-08-15 2 views
23

Ich habe viel gelesen über das Rendern von Rails Teilansichten und Ansichten in Rake-Tasks/Hintergrundjobs/Modellen. Die große Mehrheit der Dinge, die ich auf Stackoverflow und im Web gefunden habe, beschreiben Ansätze, die in Rails 3 funktionieren, aber sie scheinen veraltet zu sein und ich habe sie nicht zur Arbeit gebracht (selbst wenn ich viel Zeit mit Experimentieren verbracht habe).Rendern von Teilbildern/View in einem Rake-Task/Hintergrundjob/Modell in Rails 4

Also, wie kann ich einen Teil in einem Hintergrundjob in Rails 4 rendern?

Hier ist der beste Ansatz, den ich bisher ausgearbeitet habe (demonstriert in der Konsole).

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' 

Irgendwelche Ideen? Danke im Voraus!

Update: Die oben erwähnte tweet_path ist in der Tat nicht definiert. Dieser Fehler resultierte aus der Verknüpfung mit einem Pfad = link_to 'Tweet', [@project, tweet] (schlanke Vorlagen) mithilfe einer Instanzvariable, die in Ansichten vorhanden sein würde, die von einem bestimmten Controller erben, aber nicht, wenn sie außerhalb dieses Kontexts gerendert wurden. Ich löste dies durch die entsprechende Zuordnung statt = link_to 'Tweet', [tweet.project, tweet].

Antwort

33

Hier ist, was ich aus vielen Quellen zusammengestellt und was funktioniert für mich in Rails 4.

Mit dieser Renderer Klasse, sollten Sie in der Lage zu machen Rails 4 Ansichten und Partials in jedem Kontext, wie Hintergrundjobs, Serviceobjekte, Modelle, Arbeiter, Sie nennen es.

# 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 

aktualisieren:

Es scheint eine einfachere Lösung zu sein: 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. 

Update 2:

Es ist ein Juwel render_anywhere genannt, die für den Aufruf erlaubt " rendern "von überall: Modelle, Hintergrundjob s, Rechen Aufgaben etc.

Update 3:

In Rails 5 hat der Renderer extrahiert und kann Standalone von Hintergrundjobs und anderen Orten eingesetzt werden:

ApplicationController.renderer.render(
    partial: 'messages/message', 
    locals: { message: message } 
) 

Für Rails < = 4.2 kann diese Funktionalität mit backport_new_renderer gem rückportiert werden.

+0

Die" einfachere Lösung "funktioniert, bietet aber keinen Zugriff auf Funktionen wie" link_to ", die häufig in Vorlagen verwendet werden. Keine der beiden Lösungen scheint Zugang zu anwendungsspezifischen Helfern zu bieten. –

+0

@ JeremyBurton Du könntest ['render_anywhere'] (https://github.com/yappbox/render_anywhere) ausprobieren und sehen, ob Helfer dort enthalten sein können. –

+0

Ich löste das Problem tatsächlich, indem ich einfach die Hilfsmodule einschloss, die ich in der ViewRenderer-Klasse benötigte. Vielen Dank. –

3

Stellen Sie sicher, dass Sie die Rails-Umgebung in den Job laden. Wenn das geschehen ist, kann man so etwas versuchen:

include Rails.application.routes.url_helpers 
+0

Für Engine-URL-Helfer ist das 'MyEngine :: Engine.app.url_helpers' (Rails 4) – Jay