2013-08-15 11 views
23

rakeタスク/バックグラウンドジョブ/モデルでのRailsパーシャルとビューのレンダリングでは、多くのことを読みました。私がStackoverflowとWebで見つけた大部分のものは、Rails 3で作業するアプローチを記述していますが、古くなっているように見えます(実験にかなりの時間を費やしても)。rakeタスク/バックグラウンドジョブ/モデルのRailsでの部分/ビューのレンダリング

したがって、は、Rails 4のバックグラウンドジョブで部分的にレンダリングできますか?

これまでに私がこれまでに取り組んだ(コンソールで実証された)最良のアプローチがあります。

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' 

前もって感謝します!

更新:上記のtweet_pathは実際には定義されていません。このエラーは、特定のコントローラから継承したビューに存在するインスタンス変数を使用してパス= link_to 'Tweet', [@project, tweet](スリムテンプレート)にリンクすることによって発生しましたが、このコンテキスト外ではレンダリングされませんでした。私はこれを代わりに適切な関連付けを介して解決した= link_to 'Tweet', [tweet.project, tweet]

答えて

33

ここでは、レンダリングすることができるはず、私は情報源の多くからコンパイルし、何このレンダラークラスではRailsの4

に私の作品だ:それはすでに行われている場合は、あなたのような何かを試すことができますバックグラウンドジョブ、サービスオブジェクト、モデル、ワーカーなど、あらゆるコンテキストでのビューとパーシャルのレンダリング4名前を付けます。

# 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

ApplicationController.new.render_to_string(
    :template => 'users/index', 
    :locals => { :@users => @users } 
) 
# Mind the weird syntax to set @ variables in :locals. 

アップデート2

呼び出すことが可能になりますrender_anywhereと呼ばれる宝石」がありますどこからでもレンダリング ":モデル、バックグラウンドジョブS、すくいタスクなど

アップデート3

Railsの5で、レンダラが抽出されており、バックグラウンドジョブや他の場所からスタンドアロンで使用することができます。

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

を< = 4.2の場合、この機能はbackport_new_renderer gemでバックポートすることができます。

+0

「より簡単な解決策」は機能しますが、テンプレートでよく使用される「link_to」のような機能にはアクセスできません。どちらの解決策も、アプリケーション固有のヘルパーへのアクセスを提供していないようです。 –

+0

@JeremyBurton ['render_anywhere'](https://github.com/yappbox/render_anywhere)に試してみて、そこにヘルパーを含めることができます。 –

+0

私は実際に、ViewRendererクラスで必要なヘルパーモジュールを単に組み込むだけで、この問題を解決しました。ありがとう。 –

3

ジョブにレール環境がロードされていることを確認してください。

include Rails.application.routes.url_helpers 
+0

Engine URLヘルパーの場合は、「MyEngine :: Engine.app.url_helpers'(rails 4)」 – Jay

関連する問題