Ruby on rails RubyonRails:使用XMLBuilder部分
XML builder中的部分被证明是非常重要的 经过谷歌的初步搜索,我发现下面的方法可行,虽然不是100%Ruby on rails RubyonRails:使用XMLBuilder部分,ruby-on-rails,ruby,xml,xml-builder,Ruby On Rails,Ruby,Xml,Xml Builder,XML builder中的部分被证明是非常重要的 经过谷歌的初步搜索,我发现下面的方法可行,虽然不是100% xml.foo do xml.id(foo.id) xml.created_at(foo.created_at) xml.last_updated(foo.updated_at) foo.bars.each do |bar| xml << render(:partial => 'bar/_bar', :loca
xml.foo do
xml.id(foo.id)
xml.created_at(foo.created_at)
xml.last_updated(foo.updated_at)
foo.bars.each do |bar|
xml << render(:partial => 'bar/_bar', :locals => { :bar => bar })
end
end
xml.foo-do
xml.id(foo.id)
xml.created_at(foo.created_at)
xml.last_updated(foo.updated_at)
foo.bar.每个do | bar|
xml'bar/_-bar',:locals=>{:bar=>bar})
结束
结束
这样就可以了,除非XML输出没有正确缩进。输出类似于:
<foo>
<id>1</id>
<created_at>sometime</created_at>
<last_updated>sometime</last_updated>
<bar>
...
</bar>
<bar>
...
</bar>
</foo>
1.
在某时
在某时
...
...
元素应该在
元素下面对齐,它是
的子元素,如下所示:
<foo>
<id>1</id>
<created_at>sometime</created_at>
<last_updated>sometime</last_updated>
<bar>
...
</bar>
<bar>
...
</bar>
</foo>
1.
在某时
在某时
...
...
如果我将bar/_bar.xml.builder中的内容复制到模板中,效果会很好,但事情并不是那么简单。也许你应该做:
xml.foo do
xml.id(foo.id)
xml.created_at(foo.created_at)
xml.last_updated(foo.updated_at)
xml.bars do
foo.bars.each do |bar|
xml.bar bar.to_xml # or "xml.bar render(:xml => bar)"
# or "xml.bar render(bar)" (loads bar/_bar partial)
end
end
end
看一看
在最后一个备选方案中,您可以将内部循环替换为:
xml.bars render(foo.bars) # will loop over bars automatically using bar/_bar
您也可以尝试:
xml << foo.to_xml(:include => :bars)
xml:bar)
如果要在结果中包含所有字段
我不确定所有这些的缩进,因此您可能需要后退,以与在外部块中相同的方式创建内部循环的内容,例如不使用分部。不幸的是,没有一个直接的解决方案。当查看ActionPack将初始化生成器对象的代码时,缩进大小硬编码为2,边距大小未设置。遗憾的是,目前没有任何机制来推翻这一点 理想的解决方案是修复ActionPack,允许将这些选项传递给构建器,但这需要一些时间投资。我有两种可能的解决方法。你可以选择感觉不那么脏的那种 修改分部的渲染以渲染为字符串,然后对其执行一些正则表达式。这看起来像这样 _bar.xml.builder foos/index.xml.builder
xml.foos-do
@foos.each do|foo|
xml.foo-do
xml.id(foo.id)
xml.name(foo.name)
xml.created_at(foo.created_at)
xml.last_updated(foo.updated_at)
是的
foo.bar.每个do | bar|
xml'bar/bar',
:locals=>{:bar=>bar}).gsub(/^/,'')
结束
结束
结束
结束
结束
请注意渲染线末端的gsub。这将产生以下结果
<?xml version="1.0" encoding="UTF-8"?>
<foos>
<foo>
<id>1</id>
<name>Foo 1</name>
<created_at>2010-06-11 21:54:16 UTC</created_at>
<last_updated>2010-06-11 21:54:16 UTC</last_updated>
<bars>
<bar>
<id>1</id>
<name>Foo 1 Bar 1</name>
<created_at>2010-06-11 21:57:29 UTC</created_at>
<last_updated>2010-06-11 21:57:29 UTC</last_updated>
</bar>
</bars>
</foo>
</foos>
1.
富1
2010-06-11 21:54:16 UTC
2010-06-11 21:54:16 UTC
1.
福1巴1
2010-06-11 21:57:29 UTC
2010-06-11 21:57:29 UTC
这是一个有点黑客和肯定相当肮脏,但有一个优势是包含在您的代码。下一个解决方案是使用monkey patch ActionPack,使构建器实例按我们希望的方式工作
config/initializers/builder_mods.rb
模块操作视图
模块模板处理程序
类构建选项
cattr_存取器:边距,:缩进
结束
结束
结束
模块操作视图
模块模板处理程序
类生成器<模板处理程序
def编译(模板)
“_set_controller_content_type(Mime::XML);”+
“xml=::Builder::XmlMarkup.new(”+
:indent=>{ActionView::TemplateHandlers::BuilderOptions.indent}+
“:margin=>{ActionView::TemplateHandlers::BuilderOptions.margin})”+
“self.output_buffer=xml.target!;”+
模板源+
“xml.target!”
结束
结束
结束
结束
ActionView::TemplateHandlers::BuilderOptions.margin=0
ActionView::TemplateHandlers::BuilderOptions.indent=2
这在Rails初始化时创建了一个名为BuilderOptions的新类,其唯一目的是为缩进和边距托管2个值(尽管我们实际上只需要边距值)。我确实尝试将这些变量作为类变量直接添加到生成器模板类中,但该对象已冻结,无法更改值
创建该类后,我们在TemplateHandler中修补compile方法以使用这些值
然后,模板如下所示:-
xml.foos do
@foos.each do |foo|
xml.foo do
xml.id(foo.id)
xml.name(foo.name)
xml.created_at(foo.created_at)
xml.last_updated(foo.updated_at)
xml.bars do
ActionView::TemplateHandlers::BuilderOptions.margin = 3
foo.bars.each do |bar|
xml << render(:partial => 'bars/bar', :locals => { :bar => bar } )
end
ActionView::TemplateHandlers::BuilderOptions.margin = 0
end
end
end
end
xml.foos-do
@foos.each do|foo|
xml.foo-do
xml.id(foo.id)
xml.name(foo.name)
xml.created_at(foo.created_at)
xml.last_updated(foo.updated_at)
是的
ActionView::TemplateHandlers::BuilderOptions.margin=3
foo.bar.每个do | bar|
xml'bar/bar',:locals=>{:bar=>bar})
结束
ActionView::TemplateHandlers::BuilderOptions.margin=0
结束
结束
结束
结束
基本思想是将边距值设置为渲染局部图像时所处的缩进级别。生成的XML与上面显示的相同
请不要在没有对照Rails版本检查的情况下复制/粘贴此代码,以确保它们来自相同的代码库。(我认为上面是2.3.5)我通过在部分中作为本地文件传递builder引用来解决这个问题。没有猴子修补需要。使用原始示例:
xml.foo do
xml.id(foo.id)
xml.created_at(foo.created_at)
xml.last_updated(foo.updated_at)
foo.bars.each do |bar|
render(:partial => 'bar/_bar', :locals => {:builder => xml, :bar => bar })
end
end
然后,在局部视图中,确保使用“builder”对象
builder.bar do
builder.id bar.id
end
此外,上述内容似乎仅适用于Rails 4。Rails 5及更高版本请参见下面@srghma的评论我喜欢monkey补丁的路线,不过有一个警告:升级Rails可能会破坏此补丁或新功能。事实上,我认为这在Rails3中不起作用(不看),这就是为什么我评论说这是针对2.3.5的。很遗憾,没有一个直接的方法来钩住这种行为,因为我看到其他人想要将缩进设置为0,这也可以解决他们的问题。很好,谢谢Alex!一个警告:确保在本地哈希中重命名xml变量。我当时正在做
:locals=>{:xml=>xml}
,但这不起作用。@srghma请详述您的回答以改进解决方案。这是科雷
xml.foos do
@foos.each do |foo|
xml.foo do
xml.id(foo.id)
xml.name(foo.name)
xml.created_at(foo.created_at)
xml.last_updated(foo.updated_at)
xml.bars do
ActionView::TemplateHandlers::BuilderOptions.margin = 3
foo.bars.each do |bar|
xml << render(:partial => 'bars/bar', :locals => { :bar => bar } )
end
ActionView::TemplateHandlers::BuilderOptions.margin = 0
end
end
end
end
xml.foo do
xml.id(foo.id)
xml.created_at(foo.created_at)
xml.last_updated(foo.updated_at)
foo.bars.each do |bar|
render(:partial => 'bar/_bar', :locals => {:builder => xml, :bar => bar })
end
end
builder.bar do
builder.id bar.id
end