Brian Underwood
2010-Jun-14 19:23 UTC
XML serialization in the context of generating other Builder XML
Hey all, I''ve been spending some time trying to figure out the best way to create some XML output while mixing in ActiveRecord serialization. After looking through the source for the XmlMarkup, XmlBase, and ActiveRecord::XmlSerializer (in Rails 2. I also looked at Rails 3 and the code seems to be largely in ActiveModel) classes, the best I could find was using the "tag!" method to output the attributes/methods of an ActiveRecord object individually. Since I wanted to have all of the goodness of just specifying an array of attributes/methods/procs I ended up coding my own monkey patch (see below), but I''d love it if this sort of functionality was part of Rails so that my monkey patch doesn''t break and so that anybody could use it. If there''s no better solution currently implemented, I''d be happy to spend some time working on the project. I just thought I''d check in with ya''ll first ;) So the behavior I want would look something like this (as an sample post.xml.builder view): xml.instruct! xml.active_record_model_tag!(@post, :attributes => [:id, :body, :updated_at]) do xml.active_record_model_tag!(@post.author) @post.comments.each do |comment| xml.active_record_model_tag!(comment, :attributes => [:id, :body, :created_at], :methods => [:up_vote_percentage]) end end I also like this solution because, while I''ve been using "to_xml" for a long time and while I really like it, I think it starts to get unreasonably complex when I''m using the :only key in the options to display attributes in subsequent associations of the main object (the author and comments associations off of the @post main object in the example above) and you may get name conflicts where maybe you wanted the "created_at" for just the comments and not the post. I''ve written the (incomplete but sufficient for my needs) monkey patch below to address the issue, but again, I''d love for this to be built into Rails and for it to use the ActiveModel serialization. If it needs to be implemented, my main question is: should this be continue to be a monkey patch of Builder which is defined by Rails, or would it be best to find some way to implement it via Builder and utilize in Rails? module Builder class XmlMarkup < XmlBase def active_record_model_tag!(model_object, options = {}) undefined_keys = options.keys.collect(&:to_sym) - [:attributes, :methods] raise ArgumentError, "Undefined keys: #{undefined_keys.to_sentence}" unless undefined_keys.empty? model_class = model_object.class attributes = options[:attributes] || model_class.column_names methods = options[:methods] || [] self.tag!(model_class.to_s.tableize.singularize) do attributes.each do |attribute| value = model_object.send(attribute) type = model_class.columns_hash[attribute.to_s].type properties = {} properties = properties.merge(:type => type) if type properties = properties.merge(:nil => true) if value.nil? self.tag!(attribute, value, properties) end methods.each do |method| value = model_object.send(method) properties = properties.merge(:nil => true) if value.nil? self.tag!(method, value, properties) end yield if block_given? end end end end -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
Michael Koziarski
2010-Jun-15 03:36 UTC
Re: XML serialization in the context of generating other Builder XML
> So the behavior I want would look something like this (as an sample > post.xml.builder view): > > xml.instruct! > xml.active_record_model_tag!(@post, :attributes => > [:id, :body, :updated_at]) do > xml.active_record_model_tag!(@post.author) > @post.comments.each do |comment| > xml.active_record_model_tag!(comment, :attributes => > [:id, :body, :created_at], :methods => [:up_vote_percentage]) > end > endYou can actually get something pretty close to this already, it''s just ''backwards'' from how you''re thinking about it: xml.instruct! @post.to_xml(:builder=>xml, :skip_instruct=>true) @post.comments.each do |comment| comment.to_xml(:builder=>xml, :skip_instruct=>true) end -- Cheers Koz -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
Brian Underwood
2010-Jun-15 13:24 UTC
Re: XML serialization in the context of generating other Builder XML
Ah, excellent, thank you! I kind of like the syntax of always calling methods on the XML builder object, but this works well. I figured that if Rails supported this it probably be passing in the builder somehow. I looked at the Rails 3 documentation (beta3 from apidock: http://apidock.com/rails/v3.0.0.beta3/ActiveRecord/Serialization/to_xml ) and this option didn''t seem to be listed. Should I submit a doc patch? Thanks again, Brian ;p On Jun 14, 11:36 pm, Michael Koziarski <mich...@koziarski.com> wrote:> > So the behavior I want would look something like this (as an sample > > post.xml.builder view): > > > xml.instruct! > > xml.active_record_model_tag!(@post, :attributes => > > [:id, :body, :updated_at]) do > > xml.active_record_model_tag!(@post.author) > > @post.comments.each do |comment| > > xml.active_record_model_tag!(comment, :attributes => > > [:id, :body, :created_at], :methods => [:up_vote_percentage]) > > end > > end > > You can actually get something pretty close to this already, it''s just > ''backwards'' from how you''re thinking about it: > > xml.instruct! > @post.to_xml(:builder=>xml, :skip_instruct=>true) > @post.comments.each do |comment| > comment.to_xml(:builder=>xml, :skip_instruct=>true) > end > > -- > Cheers > > Koz-- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.
Michael Koziarski
2010-Jun-15 21:36 UTC
Re: Re: XML serialization in the context of generating other Builder XML
> I looked at the Rails 3 documentation (beta3 from apidock: > http://apidock.com/rails/v3.0.0.beta3/ActiveRecord/Serialization/to_xml > ) and this option didn''t seem to be listed. Should I submit a doc > patch?Yeah, this would probably be a good example to include. we could also consider changing to_xml to default :skip_instruct to true if :builder is provided. -- Cheers Koz -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group. To post to this group, send email to rubyonrails-core@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-core+unsubscribe@googlegroups.com. For more options, visit this group at http://groups.google.com/group/rubyonrails-core?hl=en.