RubyNewbie
2008-Nov-05 02:49 UTC
to_json() does not have behave like to_xml builder and block support
Our Rails application needs to support both xml and json formats. In some cases, we need to return custom XML that spans several objects and associations. I''ve been able to write custom to_xml methods that use the builder and block functionality. When trying the same thing with the to_json method, I failed to get the same result. Basically to_xml has this signature: to_xml(options = {}, &block). I''ve perused around and it appears to_json has this signature: to_json(options = {}). Is there a version of to_json that will yield to a block and provide the json builder? Can someone please tell me if I''ve done something wrong with the code below? Is there is a plugin or newer version of Rails that will add the same support for to_json that to_xml supports? Here is the relevant code class Conference < ActiveRecord::Base has_many :courses, :dependent => :destroy end class Course < ActiveRecord::Base belongs_to :conference has_many :sessions, :dependent => :destroy has_one :manual # just a place holder method so we can serialize it def pre_requisite "An open mind" end end class Session < ActiveRecord::Base belongs_to :courses has_one :presentation, :dependent=>:destroy # just a place holder method so we can serialize it def maximum_capacity_reached? false; end end class Presentation < ActiveRecord::Base belongs_to :session belongs_to :instructor end class Manual < ActiveRecord::Base belongs_to :course end class Instructor < ActiveRecord::Base end Now let''s suppose I have a controller that will return the full detail of a conference and needs all of the related data and will also serialize some custom methods. class ConferencesController < ApplicationController # GET /conferences/:id def show conference_id = params[:id] respond_to do |format| format.html # unsupported format.json { render(:json=>Conference.full_json(conference_id)) } format.xml { render(:xml=>Conference.full_xml(conference_id)) } end end end So I''ve extended the conference class so that it can build this nested xml along with the result of selective methods on various classes. this code uses the fact that to_xml has this signature: to_xml(options = {}, &block) class Conference < ActiveRecord::Base has_many :courses, :dependent => :destroy def slogan "#{name}: Be here or be in the dark!" end def self.full_xml(conference_id) # ensure we''ve loaded the full structure in the most efficient manner conference = Conference.find(conference_id, :include=>{:courses => [:manual, {:sessions=>:presentation}]}) # extract detailed hierarchical xml conference.to_xml do |xml| xml.slogan conference.slogan # output the banner #iterate courses and any custom methods xml.courses{ conference.courses.each do |course| course.to_xml(:builder=>xml, :skip_instruct => true) do | xml_course| xml_course.sessions{ #iterate sessions and any custom methods course.sessions.each do |session| session.to_xml(:builder=>xml_course, :skip_instruct => true) do |xml_course_session| xml_course_session.is_at_capacity session.maximum_capacity_reached? end end } end end } end end def self.full_json(conference_id) # ensure we''ve loaded the full structure in the most efficient manner conference = Conference.find(conference_id, :include=>{:courses => [:manual, {:sessions=>:presentation}]}) debugger() # extract detailed hierarchical xml conference.to_json do |json| json.slogan conference.slogan # output the banner #iterate courses and any custom methods json.courses{ conference.courses.each do |course| course.to_json(:builder=>json, :skip_instruct => true) do | json_course| json_course.sessions{ #iterate sessions and any custom methods course.sessions.each do |session| session.to_json(:builder=>json_course, :skip_instruct => true) do |json_course_session| json_course_session.is_at_capacity session.maximum_capacity_reached? end end } end end } end end end When I invoke the method, via http://localhost:3000/conferences/1.xml, I get the desired generated XML output: <conference> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <id type="integer">1</id> <name>Ruby Live</name> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> <slogan>Ruby Live: Be here or be in the dark!</slogan> - <courses> - <course> <conference-id type="integer">1</conference-id> <course-name>Action Controller: In Depth</course-name> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <id type="integer">1</id> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> - <sessions> - <session> <course-id type="integer">1</course-id> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <end-time type="datetime">2008-12-04T15:59:41-08:00</end-time> <id type="integer">1</id> <rating type="integer">4</rating> <room-number>101</room-number> <start-time type="datetime">2008-12-04T13:59:41-08:00</start-time> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> <is_at_capacity>false</is_at_capacity> </session> - <session> <course-id type="integer">1</course-id> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <end-time type="datetime">2008-12-05T15:59:41-08:00</end-time> <id type="integer">2</id> <rating type="integer">4</rating> <room-number>101</room-number> <start-time type="datetime">2008-12-05T13:59:41-08:00</start-time> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> <is_at_capacity>false</is_at_capacity> </session> </sessions> </course> + <course> <conference-id type="integer">1</conference-id> <course-name>Active Record: In Depth</course-name> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <id type="integer">2</id> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> - <sessions> - <session> <course-id type="integer">2</course-id> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <end-time type="datetime">2008-12-04T17:59:41-08:00</end-time> <id type="integer">3</id> <rating type="integer">5</rating> <room-number>201</room-number> <start-time type="datetime">2008-12-04T15:59:41-08:00</start-time> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> <is_at_capacity>false</is_at_capacity> </session> - <session> <course-id type="integer">2</course-id> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <end-time type="datetime">2008-12-05T17:59:41-08:00</end-time> <id type="integer">4</id> <rating type="integer">5</rating> <room-number>201</room-number> <start-time type="datetime">2008-12-05T15:59:41-08:00</start-time> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> <is_at_capacity>false</is_at_capacity> </session> </sessions> </course> </courses> </conference> When I invoke the method, via http://localhost:3000/conferences/1.json, I get the following undesired generated json output. Basically the builder and block that acts on to_xml is ignored or defunct. {"name": "Ruby Live", "updated_at": "2008/11/04 13:59:41 -0800", "id": 1, "created_at": "2008/11/04 13:59:41 -0800"} I need to support both xml and json formats while returning the same data. Can someone please tell me what if there is a plugin or newer version of Rails that will add this same support for to_json that to_xml supports?Our application needs to support both xml and json formats while returning the same data. In some cases, we need to return custom XML that spans several objects and associations. I''ve been able to write custom to_xml methods that use the builder and block functionality. When trying the same thing with the to_json method, I failed to get the same result. Can someone please tell me if I''ve done something wrong with the code below? Is there is a plugin or newer version of Rails that will add the same support for to_json that to_xml supports? Here is the relevant code class Conference < ActiveRecord::Base has_many :courses, :dependent => :destroy end class Course < ActiveRecord::Base belongs_to :conference has_many :sessions, :dependent => :destroy has_one :manual # just a place holder method so we can serialize it def pre_requisite "An open mind" end end class Session < ActiveRecord::Base belongs_to :courses has_one :presentation, :dependent=>:destroy # just a place holder method so we can serialize it def maximum_capacity_reached? false; end end class Presentation < ActiveRecord::Base belongs_to :session belongs_to :instructor end class Manual < ActiveRecord::Base belongs_to :course end class Instructor < ActiveRecord::Base end Now let''s suppose I have a controller that will return the full detail of a conference and needs all of the related data and will also serialize some custom methods. class ConferencesController < ApplicationController # GET /conferences/:id def show conference_id = params[:id] respond_to do |format| format.html # unsupported format.json { render(:json=>Conference.full_json(conference_id)) } format.xml { render(:xml=>Conference.full_xml(conference_id)) } end end end So I''ve extended the conference class so that it can build this nested xml along with the result of selective methods on various classes. class Conference < ActiveRecord::Base has_many :courses, :dependent => :destroy def slogan "#{name}: Be here or be in the dark!" end def self.full_xml(conference_id) # ensure we''ve loaded the full structure in the most efficient manner conference = Conference.find(conference_id, :include=>{:courses => [:manual, {:sessions=>:presentation}]}) # extract detailed hierarchical xml conference.to_xml do |xml| xml.slogan conference.slogan # output the banner #iterate courses and any custom methods xml.courses{ conference.courses.each do |course| course.to_xml(:builder=>xml, :skip_instruct => true) do | xml_course| xml_course.sessions{ #iterate sessions and any custom methods course.sessions.each do |session| session.to_xml(:builder=>xml_course, :skip_instruct => true) do |xml_course_session| xml_course_session.is_at_capacity session.maximum_capacity_reached? end end } end end } end end def self.full_json(conference_id) # ensure we''ve loaded the full structure in the most efficient manner conference = Conference.find(conference_id, :include=>{:courses => [:manual, {:sessions=>:presentation}]}) debugger() # extract detailed hierarchical xml conference.to_json do |json| json.slogan conference.slogan # output the banner #iterate courses and any custom methods json.courses{ conference.courses.each do |course| course.to_json(:builder=>json, :skip_instruct => true) do | json_course| json_course.sessions{ #iterate sessions and any custom methods course.sessions.each do |session| session.to_json(:builder=>json_course, :skip_instruct => true) do |json_course_session| json_course_session.is_at_capacity session.maximum_capacity_reached? end end } end end } end end end When I invoke the method, via http://localhost:3000/conferences/1.xml, I get the desired generated XML output: <conference> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <id type="integer">1</id> <name>Ruby Live</name> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> <slogan>Ruby Live: Be here or be in the dark!</slogan> - <courses> - <course> <conference-id type="integer">1</conference-id> <course-name>Action Controller: In Depth</course-name> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <id type="integer">1</id> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> - <sessions> - <session> <course-id type="integer">1</course-id> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <end-time type="datetime">2008-12-04T15:59:41-08:00</end-time> <id type="integer">1</id> <rating type="integer">4</rating> <room-number>101</room-number> <start-time type="datetime">2008-12-04T13:59:41-08:00</start-time> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> <is_at_capacity>false</is_at_capacity> </session> - <session> <course-id type="integer">1</course-id> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <end-time type="datetime">2008-12-05T15:59:41-08:00</end-time> <id type="integer">2</id> <rating type="integer">4</rating> <room-number>101</room-number> <start-time type="datetime">2008-12-05T13:59:41-08:00</start-time> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> <is_at_capacity>false</is_at_capacity> </session> </sessions> </course> + <course> <conference-id type="integer">1</conference-id> <course-name>Active Record: In Depth</course-name> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <id type="integer">2</id> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> - <sessions> - <session> <course-id type="integer">2</course-id> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <end-time type="datetime">2008-12-04T17:59:41-08:00</end-time> <id type="integer">3</id> <rating type="integer">5</rating> <room-number>201</room-number> <start-time type="datetime">2008-12-04T15:59:41-08:00</start-time> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> <is_at_capacity>false</is_at_capacity> </session> - <session> <course-id type="integer">2</course-id> <created-at type="datetime">2008-11-04T13:59:41-08:00</created-at> <end-time type="datetime">2008-12-05T17:59:41-08:00</end-time> <id type="integer">4</id> <rating type="integer">5</rating> <room-number>201</room-number> <start-time type="datetime">2008-12-05T15:59:41-08:00</start-time> <updated-at type="datetime">2008-11-04T13:59:41-08:00</updated-at> <is_at_capacity>false</is_at_capacity> </session> </sessions> </course> </courses> </conference> When I invoke the method, via http://localhost:3000/conferences/1.json, I get the following undesired generated json output. Basically the builder and block that acts on to_xml is ignored or defunct. {"name": "Ruby Live", "updated_at": "2008/11/04 13:59:41 -0800", "id": 1, "created_at": "2008/11/04 13:59:41 -0800"} I need to support both xml and json formats while returning the same data. Can someone please tell me what if there is a plugin or newer version of Rails that will add this same support for to_json that to_xml supports? --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Cheung
2008-Nov-05 08:54 UTC
Re: to_json() does not have behave like to_xml builder and block support
On 5 Nov 2008, at 02:49, RubyNewbie wrote:> > Our Rails application needs to support both xml and json formats. In > some cases, we need to return custom XML that spans several objects > and associations. I''ve been able to write custom to_xml methods that > use the builder and block functionality. When trying the same thing > with the to_json method, I failed to get the same result. > > Basically to_xml has this signature: to_xml(options = {}, &block). > I''ve perused around and it appears to_json has this signature: > to_json(options = {}). Is there a version of to_json that will yield > to a block > and provide the json builder? Can someone please tell me if I''ve done > something wrong with the code below? Is there is a plugin or newer > version of Rails that will add the same support for to_json that > to_xml supports?I don''t believe there is a json builder - it''s just not how the json stuff in rails works. basically there''s an obvious implementation of to_json for hashes and arrays, everything else just hangs off that (so to_json on an activerecord object basically takes the hash of attributes (module except/only etc... options) and calls to_json on it) Fred --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---