to_xml不适用于通过Rails返回的对象ActiveRecord habtm参考

我有两个rails活动记录类,School和Instructor通过has_and_belongs_to_many关系链接。

我需要查询我的instructors_controller以获取特定学校的教师并返回xml格式的响应。 因此,在索引方法中我有这个代码片段:

school = School.find(params[:school_id]) @instructors = school.instructors 

然后:

 respond_to do |format| format.html # index.html.erb format.xml { render :xml => @instructors } format.json { render :json => @instructors } end 

但它不起作用。 看看这个有趣但令人困惑的序列:

 ruby-1.9.2-p180 :023 > Instructor.all.first => # ruby-1.9.2-p180 :026 > Instructor.all.first.class => Instructor(id: integer, name: string, instructor_type_id: integer, created_at: datetime, updated_at: datetime) ruby-1.9.2-p180 :024 > School.first.instructors.first => # ruby-1.9.2-p180 :025 > School.first.instructors.first.class => Instructor(id: integer, name: string, instructor_type_id: integer, created_at: datetime, updated_at: datetime) ruby-1.9.2-p180 :021 > Instructor.all.first.to_xml => "\n\n 2011-07-24T18:19:40Z\n 1\n 1\n Mrs. Smith\n 2011-07-24T18:19:40Z\n\n" 

现在为了妙语:

 ruby-1.9.2-p180 :019 > School.first.instructors.first.to_xml NoMethodError: undefined method `type' for nil:NilClass from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activesupport-3.0.9/lib/active_support/whiny_nil.rb:48:in `method_missing' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activerecord-3.0.9/lib/active_record/serializers/xml_serializer.rb:230:in `compute_type' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:22:in `initialize' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:75:in `new' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:75:in `block in serializable_attributes' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:74:in `each' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:74:in `map' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:74:in `serializable_attributes' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:116:in `add_attributes_and_methods' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:103:in `block in serialize' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:134:in `call' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:134:in `_nested_structures' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:58:in `method_missing' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/builder-2.1.2/lib/builder/xmlbase.rb:31:in `tag!' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activemodel-3.0.9/lib/active_model/serializers/xml.rb:102:in `serialize' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/activerecord-3.0.9/lib/active_record/serializers/xml_serializer.rb:175:in `to_xml' from (irb):19 from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/railties-3.0.9/lib/rails/commands/console.rb:44:in `start' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/railties-3.0.9/lib/rails/commands/console.rb:8:in `start' from /usr/local/rvm/gems/ruby-1.9.2-p180@blueprint/gems/railties-3.0.9/lib/rails/commands.rb:23:in `' from script/rails:6:in `require' from script/rails:6:in `'ruby-1.9.2-p180 :020 > Instructor.all.first.to_xml 

这里发生了什么 ?

编辑:好吧,从xml切换到json解决了问题,(to_json在这里没有表现出与to_xml相同的陌生感),尽管我仍然想知道上述行为的解释。

另外,由于我对Rails相对较新,有没有更好的方法来做我想做的事情?

to_xml()尝试为每个模型属性定义一个type属性。 例如,具有age(INT)属性的User模型将具有: 42 。 此类型信息不是以JSON编码的,这就是为什么to_json()适合您。 将此方法添加到您的Instructor模型:

 def to_xml(options = {}) to_xml_opts = {:skip_types => true} # no type information, not such a great idea! to_xml_opts.merge!(options.slice(:builder, :skip_instruct)) # a builder instance is provided when to_xml is called on a collection of instructors, # in which case you would not want to have  added to each item to_xml_opts[:root] ||= "instructor" self.attributes.to_xml(to_xml_opts) end 

但是这会使您的XML缺少任何类型信息 – 如果有人拥有JAVA REST客户端则不好。 更好的策略是过滤self.attributes.slice(*keys).to_xml(to_xml_opts) ,其中keys是XML中所需的模型属性数组。