如何在Rails中渲染不同格式的局部图像?


114

我正在尝试生成包含一些HTML的JSON响应。因此,我有/app/views/foo/bar.json.erb

{
  someKey: 'some value',
  someHTML: "<%= h render(:partial => '/foo/baz') -%>"
}

我要它渲染/app/views/foo/_baz.html.erb,但只会渲染/app/views/foo/_baz.json.erb。通过:format => 'html'无济于事。


问题标题比詹姆斯的特定问题笼统得多。如果您正在寻找其他的解决方案,看看这里:stackoverflow.com/questions/7616097/...
miguelsan

Answers:


100

从Rails 3.2.3开始,在调用render:partial时(仅在respond_to块外部起作用)。

render formats: [ :html ]

代替

render format: 'html'

我想根据上下文可能会有不同的“最佳”答案,因此很难对此问题进行有意义的投票,但这满足了我的需求,即希望一个:format选项将在同名RJS中轻松呈现HTML模板。工作。谢谢!
ches

1
这也适用于Rails 5.0.2。但是,请注意,:content_type在某些情况下,您可能还需要指定该选项-例如,format.pdf只能使用来从块内部渲染HTML模板render "template", formats: [:html], content_type: "text/html"。我之所以需要这样做,是因为我只允许直接为我的电子邮件列表中的成员下载图书样本-常规访问者会获得注册表格。
Michael Trojanek'3

64

怎么了

render :partial => '/foo/baz.html.erb'

?我只是尝试通过Atom构建器模板内部呈现HTML ERB部分,并且效果很好。无需弄乱全局变量(是的,我知道它们前面有“ @”,但这就是它们)。

但是,您的with_format &block方法很酷,并且具有只指定格式的优点,而简单的方法也可以指定模板引擎(ERB / builder / etc)。


26
唯一的缺点是,如果您的部分渲染其他部分,则除非您进入并更改所有渲染部分调用以在其名称中包含“ .html.erb”,否则它将失败。
chrisrbailey

4
您不必为此指定模板引擎。(至少从导轨3起)。以下工作正常:render(:partial =>“ baz.html”)
Tim Harper 2010年

1
如果你有不同的地区不同的谐音(如不行的baz.en.html.erbbaz.fr.html.erb),你想render :partialS代表选择是正确的逻辑(与回退等)。
约翰

1
从rails 3.2.3开始,使用此解决方案时会看到以下警告:DEPRECATION WARNING: Passing a template handler in the template name is deprecated. You can simply remove the handler name or pass render :handlers => [:erb] instead.
YWCA您好

3
这种方法的缺点是,本地化将foo.baz.html.[your_string]代替foo.baz.[your_string]。zgchurc的答案是一个更好的解决方案。
mbillard

32

对于Rails 3,with_format块可以工作,但是有点不同:

  def with_format(format, &block)
    old_formats = formats
    self.formats = [format]
    block.call
    self.formats = old_formats
    nil
  end

也适用于rails 3.2.0 :)
gucki 2012年

32

Rails 4将允许您传递format参数。所以你可以做

render(:partial => 'form', :formats => [:html])} 

请注意,您可以在Rails 3中执行类似的操作,但不会将该格式传递给任何子部分(如果表单调用其他部分)。

通过创建config / initializers / renderer.rb,可以在Rails 3中具有Rails 4功能:

class ActionView::PartialRenderer
  private
  def setup_with_formats(context, options, block)
    formats = Array(options[:formats])
    @lookup_context.formats = formats | @lookup_context.formats
    setup_without_formats(context, options, block)
  end

  alias_method_chain :setup, :formats
end

参见http://railsguides.net/2012/08/29/rails3-does-not-render-partial-for-specific-format/


奇怪,我想知道为什么它在Rails 3.2.19应用程序中对我不起作用,想知道是什么使我的应用程序与众不同。即使使用此修补程序,也无法使ActionView render:partial尊重:formats arg,似乎没有任何区别。
jrochkind 2014年

29

基于roninek的响应,我发现最好的解决方案是:

在/app/helpers/application.rb中:

def with_format(format, &block)
  old_format = @template_format
  @template_format = format
  result = block.call
  @template_format = old_format
  return result
end

在/app/views/foo/bar.json中:

<% with_format('html') do %>
  <%= h render(:partial => '/foo/baz') %>
<% end %>

另一种解决方案是重新定义render以接受:format参数。

我不能render :file和当地人一起工作,并且没有一点路途的困惑。


8
太烂了 最好指定整个扩展名。
蒂姆·哈珀

1
对于rails 3,请参见zgchurch的答案。
lillq 2010年

25

在Rails 3中,视图具有一个formats数组,这意味着您可以将其设置为查找[:mobile,:html]。设置默认为寻找:mobile模板,但回退为:html模板。设置此项的效果将逐步分解为内部部分。

我可以找到的最好但仍然有缺陷的方法是将这一行放在每个完整移动模板的顶部(但不包括部分模板)。

<% self.formats = [:mobile, :html] %>

缺点是您必须将该行添加到多个模板。如果有人从application_controller.rb中知道一次设置此方法的方法,我很想知道。不幸的是,将那条线添加到您的移动布局中是行不通的,因为模板是在布局之前渲染的。


感谢您的解释。最后我用它在别处:stackoverflow.com/questions/47459724/...
约书亚品特

16

只需详细说明zgchurch写道:

  • 考虑例外
  • 返回被调用块的结果

认为可能有用。

def with_format(format, &block)
  old_formats = formats
  begin
    self.formats = [format]
    return block.call
  ensure
    self.formats = old_formats
  end
end

10

您有两种选择:

1)使用 render :file

render :file => "foo/_baz.json.erb"

2)通过设置@template_format变量将模板格式更改为html

<% @template_format = "html" %>
<%= h render(:partial => '/foo/baz') %>

1
<%@template_format =“ html”%>为我工作,因为我的局部加载了其他局部,因此我不必更新链中的其他渲染。
pagetribe 2011年

5

我有一个名为“ api / item.rabl”的文件,我想从HTML视图中呈现它,所以我必须使用:

render file: 'api/item', formats: [:json]

file因为文件名中没有下划线,formats并且没有format(并且通过和数组))


2

似乎通过一个formats选项将在至少3.2的较新版本的Rails中正确呈现它:

{
  someKey: 'some value',
  someHTML: "<%= h render('baz', formats: :html) -%>"
}

1

当我尝试在另一个xml.builder视图文件中呈现XML部分时,遇到了这个线程。以下是一个很好的方法

xml.items :type => "array" do
    @items.each do |item|
        xml << render(:partial => 'shared/partial.xml.builder', :locals => { :item => item })
    end
end

是的...完整的文件名在这里也适用...


这也遇到了@chrisrbailey在另一个答案中提到的相同的inner-partials-problem问题:如果使用完整文件名调用的partial本身使用了partials(未为每个文件名指定完整文件名),它将失败。
詹姆斯·A·罗森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.