2013-08-15 12 views
23

Dużo czytałem na temat renderowania części i widoków Railsowych w zadaniach rake/background jobs/models. Zdecydowana większość rzeczy, które znalazłem na Stackoverflow i sieci opisuje podejścia działające w Railsach 3, ale wydają się przestarzałe i nie udało mi się ich uruchomić (nawet przy dość długim czasie eksperymentowania).Renderowanie części/widok w zadaniu rake/background job/model w Railsach 4

Jak zatem mogę renderować częściowe w pracy w tle w Rails 4?

Oto najlepsze podejście, jakie wypracowałem do tej pory (wykazane w konsoli).

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' 

Jakieś pomysły? Z góry dziękuję!

Aktualizacja: Wymieniona wyżej tweet_path jest rzeczywiście niezdefiniowana. Ten błąd wynikał z połączenia ze ścieżką = link_to 'Tweet', [@project, tweet] (wąskie szablony) przy użyciu zmiennej instancyjnej, która byłaby obecna w widokach dziedziczących z określonego kontrolera, ale nie w przypadku renderowania poza tym kontekstem. Rozwiązałem to poprzez odpowiednie powiązanie zamiast tego = link_to 'Tweet', [tweet.project, tweet].

Odpowiedz

33

Oto co skompilowany z wielu źródeł i co działa na mnie w Rails 4.

Z tej klasie Renderer, powinieneś być w stanie renderować Rails 4 widoki i częściowe w dowolnym kontekście, takie jak zadania w tle, obiekty usług, modele, pracownicy, ty go nazwij.

# 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 

Aktualizacja:

Nie wydaje się być łatwiejsze rozwiązanie: 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. 

Aktualizacja 2:

Jest to klejnot zwany render_anywhere która pozwala na wywołanie " renderuj "z dowolnego miejsca: modele, zadania w tle s, zadania Rake, itp

Update 3:

W Szyny 5, renderer zostały wyodrębnione i mogą być używane samodzielnie tła z pracy i innych miejscach:

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

W przypadku Railsów < = 4.2 ta funkcja może być przeniesiona z backport_new_renderer gem.

+0

" Łatwiejsze rozwiązanie "działa, ale nie zapewnia dostępu do takich funkcji jak" link_to ", które są powszechnie używane w szablonach. Żadne z tych rozwiązań nie zapewnia dostępu do pomocy specyficznych dla aplikacji. –

+0

@JeremyBurton Możesz dać ['render_anywhere'] (https://github.com/yappbox/render_anywhere) spróbować i sprawdzić, czy można tam dodać pomocników. –

+0

Rzeczywiście rozwiązałem problem, włączając po prostu moduły pomocnicze, których potrzebowałem w klasie ViewRenderer. Dzięki. –

3

Upewnij się, że ładujesz środowisko szyn w zadaniu. Jeśli to już jest zrobione można spróbować coś takiego:

include Rails.application.routes.url_helpers 
+0

Dla pomocników URL silnika to 'MyEngine :: Engine.app.url_helpers' (rails 4) – Jay

Powiązane problemy