Reputation: 196
I've updated my server to ruby 1.9.2 and this stopped working (rails 3.0.6):
def index
@musicians = Musician.includes(:instruments)
render :xml => @musicians.to_xml( :include => :instruments )
end
And the models:
class Musician < ActiveRecord::Base
has_and_belongs_to_many :instruments
end
class Instrument < ActiveRecord::Base
has_and_belongs_to_many :musicians
end
I'm getting this error:
undefined method `type' for nil:NilClass
Framework trace:
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'
Any clue what I'm doing wrong?
Maybe this is related to: https://rails.lighthouseapp.com/projects/8994/tickets/4840-to_xml-doesnt-work-in-such-case-eventselecttitle-as-tto_xml
Upvotes: 1
Views: 1065
Reputation: 1875
Here is a workaround that did the trick for me.
I converted all the active record objects to hashes using the attributes call which fixed the issue for me
@musicians = @musicians.map{|a| a.attributes}
@musicians.to_xml
Upvotes: 0
Reputation: 989
This is a core issue with Rails. What's happening is that when Instruments are being included, an instrument_id
attribute is getting added. Then, when each Instrument is serialized, the XmlSerializer class determines the type of that attribute based on the Instrument class' definition, using the type attribute for each column. Since the instrument_id
attribute does not exist in the class definition, a nil object is returned which, as of Ruby 1.9, does not have a type
attribute, which Rails is depending on.
(I don't think the patch in the thread you linked to works -- but the one I've provided below does.)
There are two ways to fix this:
instrument_id
(good idea).
render :xml => @musicians.to_xml( :include => { :instruments => { :except => :instrument_id } } )
--- 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
Upvotes: 4
Reputation: 7909
I guess if you are using HABTM
association you should have a join table called musicians_instruments
you have to include that nested as well.
render :xml => @musicians.to_xml( :include => {:musicians_instruments =>{:include=>:instruments}} )
Note that the include is different than in ActiveRecord
associations.
Update
If you create a model for the join table, you can change the has_and_belongs_to_many
to a has_many :through
, its used more often and does the same.
#musician.rb
has_many :musicians_instruments
has_many :instruments, :through=>:musicians_instruments
#instrument.rb
has_many :musicians_instruments
has_many :musicians, :through=>:musicians_instruments
This one should work properly with the to_xml
nested includes.
Upvotes: 0