to_xml include在rails 3.0.6 ruby​​ 1.9.2中不起作用

时间:2011-04-14 09:57:36

标签: ruby-on-rails xml include

我已将服务器更新为ruby 1.9.2并且此操作已停止(rails 3.0.6):

def index  
  @musicians = Musician.includes(:instruments)
  render :xml => @musicians.to_xml( :include => :instruments )
end

模特:

class Musician < ActiveRecord::Base
  has_and_belongs_to_many :instruments
end

class Instrument < ActiveRecord::Base
  has_and_belongs_to_many :musicians
end

我收到了这个错误:

undefined method `type' for nil:NilClass

框架追踪:

activesupport (3.0.6) lib/active_support/whiny_nil.rb:48:in `method_missing'
activerecord (3.0.6) lib/active_record/serializers/xml_serializer.rb:230:in `compute_type'
activemodel (3.0.6) lib/active_model/serializers/xml.rb:22:in `initialize'
activemodel (3.0.6) lib/active_model/serializers/xml.rb:75:in `new'
activemodel (3.0.6) lib/active_model/serializers/xml.rb:75:in `block in serializable_attributes'

有什么迹象表明我做错了什么?

这可能与:https://rails.lighthouseapp.com/projects/8994/tickets/4840-to_xml-doesnt-work-in-such-case-eventselecttitle-as-tto_xml

有关

3 个答案:

答案 0 :(得分:4)

这是Rails的核心问题。发生的事情是,当包含Instruments时,会添加instrument_id属性。然后,当序列化每个Instrument时,XmlSerializer类使用每个列的type属性,根据Instrument类的定义确定该属性的类型。由于类定义中不存在instrument_id属性,因此返回一个nil对象,从Ruby 1.9开始,它没有type属性,Rails依赖于该属性。

(我不认为您链接的主题中的补丁有效 - 但我在下面提供的补丁确实如此。)

有两种方法可以解决这个问题:

  1. 不要序列化instrument_id(好主意)。
    render :xml => @musicians.to_xml( :include => { :instruments => { :except => :instrument_id } } )
  2. 或补丁Rails核心(坏主意)。
    --- a/activerecord/lib/active_record/serializers/xml_serializer.rb  2011-04-20 15:01:10.000000000 -0700
    +++ b/activerecord/lib/active_record/serializers/xml_serializer.rb      2011-04-20 15:00:42.000000000 -0700
    @@ -226,8 +226,10 @@
    
         class Attribute < ActiveModel::Serializers::Xml::Serializer::Attribute #:nodoc:
           def compute_type
    +        Rails.logger.info("key: #{name}, hash: #{@serializable.class.columns_hash[name]}")
             type = @serializable.class.serialized_attributes.has_key?(name) ?
    -          super : @serializable.class.columns_hash[name].type
    +          super : @serializable.class.columns_hash[name].nil? ?
    +            NilClass : @serializable.class.columns_hash[name].type
    
             case type
             when :text

答案 1 :(得分:0)

我想如果您使用的是HABTM关联,那么您应该有一个名为musicians_instruments的连接表,您必须包含该嵌套。

render :xml => @musicians.to_xml( :include => {:musicians_instruments =>{:include=>:instruments}} )

请注意,include与ActiveRecord关联不同。

<强>更新

如果您为联接表创建了一个模型,则可以将has_and_belongs_to_many更改为has_many :through,其使用频率更高并且也相同。

#musician.rb
has_many :musicians_instruments
has_many :instruments, :through=>:musicians_instruments

#instrument.rb
has_many :musicians_instruments
has_many :musicians, :through=>:musicians_instruments

这个应该适用于to_xml嵌套包含。

答案 2 :(得分:0)

这是一个为我解决问题的解决方法。

我使用为我修复问题的属性调用将所有活动记录对象转换为哈希

@musicians = @ musicians.map {| a | a.attributes}

@ musicians.to_xml