Rendering partial / views in a rake task / background job / model in Rails 4

I read a lot about rendering of Rails partitions and representations in rake tasks / background tasks / models. The vast majority of the things that I have found on Stackoverflow and on the Internet describe approaches that work in Rails 3, but they seem deprecated, and I did not make them work (even with a fairly lengthy experiment).

So how can I do partial in a background job in Rails 4?

Here is the best approach that I have developed 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!

Update: tweet_path mentioned above is really undefined. This error occurred due to the link to the path = link_to 'Tweet', [@project, tweet] (slim templates) using an instance variable that will be present in the views inherited from the specific controller, but not when rendering outside this context. I solved this through the appropriate association instead of = link_to 'Tweet', [tweet.project, tweet] .

+23
ruby ruby-on-rails ruby-on-rails-4
Aug 15 '13 at 22:54
source share
2 answers

Here is what I have compiled from a large number of sources and what works for me in Rails 4.

With this Renderer class, you can display Rails 4 and partial parts in any context, such as 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 

Update

There seems to be a simpler 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. 

Update 2 :

There is a gem called render_anywhere that allows you to call "rendering" from anywhere: models, background jobs, rake tasks, etc.

Update 3 :

In Rails 5, rendering was extracted and can be used autonomously from background jobs and other places:

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

For Rails <= 4.2, this function can be passed using the backport_new_renderer gem .

+31
Aug 16 '13 at 5:36 on
source share

Make sure you load the rail environment into the job. If this has already been done, you can try something like:

 include Rails.application.routes.url_helpers 
+2
Aug 15 '13 at 23:26
source share



All Articles