Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails RubyonRails:使用XMLBuilder部分_Ruby On Rails_Ruby_Xml_Xml Builder - Fatal编程技术网

Ruby on rails RubyonRails:使用XMLBuilder部分

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 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', :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