为父级而不是子级覆盖ActiveRecord :: Base#to_xml

时间:2015-03-15 04:34:49

标签: ruby-on-rails xml activerecord override builder

我有一个activerecord模型,其中包含一些在为API生成xml时需要覆盖的属性。描述如何编写自定义to_xml方法的说明here可以正常工作。

我遇到的问题是模型处于相当深的关系系统的顶层,手动指定所有后代的xml生成将是一项巨大的工作。是否有任何方法可以将控制权交给Builder进行关系,这样它就可以自动生成xml,就像我必须覆盖之前一样?

以下是我想做的一个例子:

class IHaveMyOwnXML < ActiveRecord::Base
  has_many :widgets
  def to_xml(options = {})
    options[:indent] ||= 2
    xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
    xml.instruct! unless options[:skip_instruct]
    xml.level_one do
      xml.tag!(:second_level, 'content')
    end
    xml.pick_up_where_you_left_off! widgets
  end
end

显然pick_up_where_you_left_off!不存在。我想要的是在xml doc中注入此widgets的xml,看起来就像我没有完成覆盖一样,并调用了IHaveMyOwnXML#to_xml(:include =&gt;:窗口小部件)。

这可能吗?或者,一旦覆盖ActiveRecord#to_xml,您是否承诺为任意深度嵌套的AR关系手动编码xml生成?

我已经尝试了第一个建议,虽然它本身很好,但我无法告诉如何在我的自定义to_xml方法中注入关系。以下工作都不是:

xml.household do
  xml.id id
  xml.accounts accounts
end

xml.household do
  xml.id id
  xml << accounts.to_xml # also w/ (opts.merge(:builder => xml))
end

第一个只给出一个ruby对象引用(<accounts>#&lt;Account:0x10abb5250&gt;</accounts>)。第二个注入一个完整的xml文档,其中household节点作为根,以及一个xml声明。

1 个答案:

答案 0 :(得分:0)

我认为你可以通过这样做来实现这个目标:

如果模型需要自定义xml

,则定义一个方法
# Parent
def use_custom_xml?
  true
end

# Child
def use_custom_xml?
  false
end

现在您可以在父代上编写自定义xml生成器,如下所示:

def to_xml(options = {})
  return super unless use_custom_xml?
  # ... your custom code
end

我没有尝试过这个用于xml的生成,但我使用了类似的模式,它对我有用。