Rendering partials / view in a rake task / background job / model in Rails 4

后端 未结 2 560
终归单人心
终归单人心 2021-02-01 17:24

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

2条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-02-01 18:24

    Here's what I compiled from lots of sources and what works for me in 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
    

    Update:

    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.
    

    Update 2:

    There's a gem called render_anywhere that allows for calling "render" from anywhere: models, background jobs, rake tasks, etc.

    Update 3:

    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 }
    )
    

    For Rails <= 4.2, this functionality can be backported with the backport_new_renderer gem.

提交回复
热议问题