Подтвердить что ты не робот

Оказание частичных/представлений в задаче rake/фоновом задании/модели в Rails 4

Я много читал о рендеринге партиций Rails и представлений в рейк-задачах/фоновых заданиях/моделях. Подавляющее большинство вещей, которые я нашел в Stackoverflow и в Интернете, описывают подходы, работающие в Rails 3, но они кажутся устаревшими, и я не заставил их работать (даже с довольно продолжительным экспериментом).

Итак, как я могу выполнить частичное в фоновом задании в 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] (slim templates) с использованием переменной экземпляра, которая будет присутствовать в представлениях, наследуемых от определенного контроллера, но не при визуализации вне этого контекста. Я решил это через соответствующую ассоциацию вместо = link_to 'Tweet', [tweet.project, tweet].

4b9b3361

Ответ 1

Вот что я собрал из большого количества источников и что работает для меня в Rails 4.

С помощью этого класса Renderer вы сможете отображать Rails 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, который позволяет вызывать "рендеринг" из любого места: модели, фоновые задания, задачи грабли и т.д.

Обновление 3:

В Rails 5 рендеринг был извлечен и может использоваться автономно из фоновых заданий и других мест:

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

Для Rails <= 4.2 эта функция может быть передана с помощью backport_new_renderer gem.

Ответ 2

Убедитесь, что вы загружаете среду рельсов в задание. Если это уже сделано, вы можете попробовать что-то вроде:

include Rails.application.routes.url_helpers