2011-01-13 63 views
5

在我的Rails应用程序中,我有一个操作,它使用XML Builder模板(rxml)模板和render_to_string创建XML文档。 XML文档被转发到后端服务器。如何在使用render_to_string后正常呈现视图?

创建XML文档后,我想向浏览器发送一个普通的HTML响应,但不知何故Rails正在记住第一次拨打render_to_string

例如:因为它看起来为show.rxml

  • Rails可以找不到默认视图show.html.erb
  • 简单地将render 'mycontroller/show.html.erb'放在我的动作句柄的底部会使Rails找到模板,但浏览器不起作用,因为响应标头的内容类型为text/xml

有没有什么办法可以使用render_to_string而不会“玷污”实际的浏览器响应?

编辑:看来,在Rails 2 erase_render_results会做的伎俩,但在Rails 3它不再可用。

+0

实际上`erase_render_results`只是设置一个标记为false并擦除response_body - 在render_to_string的源代码中,内容类型显式设置为nil。这似乎更可能是您遇到的问题是由于。 – 2011-01-13 21:30:10

回答

2

实用的答案是使用视图文件和两个调用来呈现是不是Rails方式:视图通常是发送到客户端的东西,并且ActionPack被设计为以这种方式工作。

也就是说,有一个简单的方法可以实现你想要做的事情。而不是使用的ActionView,你可以使用生成器:: XmlMarkup中直接生成您的XML作为一个字符串:

def action_in_controller 
    buffer = "" 
    xml = Builder::XmlMarkup.new(buffer) 

    # build your XML - essentially copy your view.xml.builder file here 
    xml.element("value") 
    xml.element("value") 

    # send the contents of buffer to your 3rd server 

    # allow your controller to render your view normally 
end 

看一看the Builder documentation来看看它是如何工作的。

您可以利用的Builder的另一个功能是使用<<将XML内容附加到缓冲区,因此可以使用任何IO流。根据你将内容发送到其他服务器的方式,你可以很好地包装它。

当然,这可能会非常混乱和漫长,这就是为什么你想要将这些功能封装在另一个类中,或者作为模型中的方法。

+1

问题是XML数据也必须作为普通视图提供,所以遵循你的建议意味着复制代码(在我的情况下)尽管如此,这是我所做的,谢谢。 – 2011-01-14 19:49:58

2

好像这可能是rails 3中的一个bug(至少与2.3.x render_to_string的行为相比)。在source for 2.3.8中,他们显然需要额外的步骤来重置content_type并将响应主体设置为零(除其他外)。

def render_to_string 
    ... 
ensure 
    response.content_type = nil 
    erase_render_results 
    reset_variables_added_to_assigns 
end 

但在3.0.3源AbstractController::Rendering

def render_to_string(*args, &block) 
    options = _normalize_args(*args, &block) 
    _normalize_options(options) 
    render_to_body(options) 
end 

你可以看到有变量没有明确的复位,render_to_body只是返回view_context.render。这可能是内容类型,response_body等在其他地方处理,这是一个红色的鲱鱼,但我的第一本能是设置

response.headers['Content-Type'] = 'text/html'

render_to_string后实际渲染之前。

2

在迁移actionwebservice gem时,我遇到了同样的错误。在他们的代码中,他们通过调用函数erase_render_results来规避双重渲染异常。

该功能在rails3中不再可用。幸运的是修复很容易(但我花了一段时间才找到)。

内actionwebservice下面的函数被调用一个控制器内,使第二渲染:

def reset_invocation_response 
    erase_render_results 
    response.instance_variable_set :@header, Rack::Utils::HeaderHash.new(::ActionController::Response::DEFAULT_HEADERS.merge("cookie" => [])) 
end 

要在Rails3中这项工作,你就必须写:

def reset_invocation_response 
    self.instance_variable_set(:@_response_body, nil) 
    response.instance_variable_set :@header, Rack::Utils::HeaderHash.new("cookie" => [], 'Content-Type' => 'text/html') 
end 

希望这有助于。

+0

+1非常有帮助,你得到5个互联网! – 2011-08-01 17:25:29