Rails: Render view from outside controller

2019-01-23 13:43发布

问题:

I'm trying to create an HTML string using a view. I would like to render this from a class that is not a controller. How can I use the rails rendering engine outside a controller? Similar to how ActionMailer does?

Thanks!

回答1:

Rails 5 now supports this in a much more convenient manner that handles creating a request and whatnot behind the scenes:

rendered_string = ApplicationController.render(
  template: 'users/show',
  assigns: { user: @user }
)

This renders app/views/users/show.html.erb and sets the @user instance variable so you don't need to make any changes to your template. It automatically uses the layout specified in ApplicationController (application.html.erb by default).

The test shows a handful of additional options and approaches.



回答2:

You can use ActionView::Base to achieve this.

view = ActionView::Base.new(ActionController::Base.view_paths, {})
view.render(file: 'template.html.erb')

The ActionView::Base initialize takes:

  1. A context, representing the template search paths
  2. An assigns hash, providing the variables for the template

If you would like to include helpers, you can use class_eval to include them:

view.class_eval do
  include ApplicationHelper
  # any other custom helpers can be included here
end


回答3:

There is no need to over bloat your app with too many gems. As we know ERB is already included in your Rails app.

@jdf = JDF.new
@job = ERB.new(File.read(Rails.root + "app/views/entries/job.xml.erb"))
result =  @job.result(binding)

Above there is snippet of code of an app I'm working on.

  • @jdf is a object to be evaluated in the erb view.
  • In my case I needed to render xml.
  • result is a string to be saved or sent anywhere you like.


回答4:

Technically, ActionMailer is a subclass implementation of AbstractController::Base. If you want to implement this functionality on your own, you'll likely want to inherit from AbstractController::Base as well.

There is a good blog post here: https://www.amberbit.com/blog/2011/12/27/render-views-and-partials-outside-controllers-in-rails-3/ that explains the steps required.



回答5:

For future reference, I ended up finding this handy gem that makes this a breeze:

https://github.com/yappbox/render_anywhere



回答6:

"I'm trying to create an HTML string using a view." -- If you mean you're in the context of a view template, then just use a helper method or render a partial.

If you're in some other "Plain Old Ruby Object", then keep in mind you're free to use the ERB module directly:

erb = ERB.new("path/to/template")
result = erb.result(binding)

The trick is getting that 'binding' object that gives the context for the code in the template. ActionController and other Rails classes expose it for free, but I couldn't find a reference that explains where it comes from.

http://www.ruby-doc.org/stdlib-2.2.0/libdoc/erb/rdoc/ERB.html#method-i-result



回答7:

Best to render the view using a controller, as that's what they're for, and then convert it to a string, as that is your ultimate goal.

require 'open-uri'
html = open(url, &:read)