Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 7663

Show
Ignore:
Timestamp:
09/28/07 14:07:23 (8 months ago)
Author:
david
Message:

Added :include option to to_json (closes #9677) [chuyeow]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activerecord/CHANGELOG

    r7662 r7663  
    1111* Added the possibility of using symbols in addition to concrete classes with ActiveRecord::Observer#observe #3998 [robbyrussell/tarmo] 
    1212 
    13 * Added ActiveRecord::Base#to_json/from_json (currently does not support :include like to_xml) [DHH
     13* Added ActiveRecord::Base#to_json/from_json [DHH/chuyeow
    1414 
    1515* Added ActiveRecord::Base#from_xml [DHH]. Example: 
  • trunk/activerecord/lib/active_record/serialization.rb

    r7519 r7663  
    33    class Serializer #:nodoc: 
    44      attr_reader :options 
    5      
     5 
    66      def initialize(record, options = {}) 
    77        @record, @options = record, options.dup 
     
    2424          attribute_names = attribute_names - options[:except].collect { |n| n.to_s } 
    2525        end 
    26        
     26 
    2727        attribute_names 
    2828      end 
     
    3030      def serializable_method_names 
    3131        Array(options[:methods]).inject([]) do |method_attributes, name| 
    32           method_attributes << :name if @record.respond_to?(name.to_s) 
     32          method_attributes << name if @record.respond_to?(name.to_s) 
    3333          method_attributes 
    3434        end 
    3535      end 
    36        
     36 
    3737      def serializable_names 
    3838        serializable_attribute_names + serializable_method_names 
     39      end 
     40 
     41      # Add associations specified via the :includes option. 
     42      # Expects a block that takes as arguments: 
     43      #   +association+ - name of the association 
     44      #   +records+     - the association record(s) to be serialized 
     45      #   +opts+        - options for the association records 
     46      def add_includes(&block) 
     47        if include_associations = options.delete(:include) 
     48          base_only_or_except = { :except => options[:except], 
     49                                  :only => options[:only] } 
     50 
     51          include_has_options = include_associations.is_a?(Hash) 
     52          associations = include_has_options ? include_associations.keys : Array(include_associations) 
     53 
     54          for association in associations 
     55            records = case @record.class.reflect_on_association(association).macro 
     56            when :has_many, :has_and_belongs_to_many 
     57              @record.send(association).to_a 
     58            when :has_one, :belongs_to 
     59              @record.send(association) 
     60            end 
     61 
     62            unless records.nil? 
     63              association_options = include_has_options ? include_associations[association] : base_only_or_except 
     64              opts = options.merge(association_options) 
     65              yield(association, records, opts) 
     66            end 
     67          end 
     68 
     69          options[:include] = include_associations 
     70        end 
    3971      end 
    4072 
     
    4274        returning(serializable_record = {}) do 
    4375          serializable_names.each { |name| serializable_record[name] = @record.send(name) } 
     76          add_includes do |association, records, opts| 
     77            if records.is_a?(Enumerable) 
     78              serializable_record[association] = records.collect { |r| self.class.new(r, opts).serializable_record } 
     79            else 
     80              serializable_record[association] = self.class.new(records, opts).serializable_record 
     81            end 
     82          end 
    4483        end 
    4584      end 
     
    4786      def serialize 
    4887        # overwrite to implement 
    49       end         
    50      
     88      end 
     89 
    5190      def to_s(&block) 
    5291        serialize(&block) 
  • trunk/activerecord/lib/active_record/serializers/xml_serializer.rb

    r7519 r7663  
    142142          options[:skip_instruct] = true 
    143143        end 
    144          
     144 
    145145        builder 
    146146      end 
     
    151151      dasherize? ? root.dasherize : root 
    152152    end 
    153      
     153 
    154154    def dasherize? 
    155155      !options.has_key?(:dasherize) || options[:dasherize] 
     
    180180    end 
    181181 
    182     def add_includes 
    183       if include_associations = options.delete(:include) 
    184         root_only_or_except = { :except => options[:except], 
    185                                 :only => options[:only] } 
    186  
    187         include_has_options = include_associations.is_a?(Hash) 
    188  
    189         for association in include_has_options ? include_associations.keys : Array(include_associations) 
    190           association_options = include_has_options ? include_associations[association] : root_only_or_except 
    191  
    192           opts = options.merge(association_options) 
    193  
    194           case @record.class.reflect_on_association(association).macro 
    195           when :has_many, :has_and_belongs_to_many 
    196             records = @record.send(association).to_a 
    197             tag = association.to_s 
    198             tag = tag.dasherize if dasherize? 
    199             if records.empty? 
    200               builder.tag!(tag, :type => :array) 
    201             else 
    202               builder.tag!(tag, :type => :array) do 
    203                 association_name = association.to_s.singularize 
    204                 records.each do |record|  
    205                   record.to_xml opts.merge( 
    206                     :root => association_name,  
    207                     :type => (record.class.to_s.underscore == association_name ? nil : record.class.name) 
    208                   ) 
    209                 end 
    210               end 
    211             end 
    212           when :has_one, :belongs_to 
    213             if record = @record.send(association) 
    214               record.to_xml(opts.merge(:root => association)) 
    215             end 
    216           end 
    217         end 
    218  
    219         options[:include] = include_associations 
    220       end 
    221     end 
    222  
    223182    def add_procs 
    224183      if procs = options.delete(:procs) 
     
    228187      end 
    229188    end 
    230  
    231189 
    232190    def add_tag(attribute) 
     
    238196    end 
    239197 
     198    def add_associations(association, records, opts) 
     199      if records.is_a?(Enumerable) 
     200        tag = association.to_s 
     201        tag = tag.dasherize if dasherize? 
     202        if records.empty? 
     203          builder.tag!(tag, :type => :array) 
     204        else 
     205          builder.tag!(tag, :type => :array) do 
     206            association_name = association.to_s.singularize 
     207            records.each do |record|  
     208              record.to_xml opts.merge( 
     209                :root => association_name,  
     210                :type => (record.class.to_s.underscore == association_name ? nil : record.class.name) 
     211              ) 
     212            end 
     213          end 
     214        end 
     215      else 
     216        if record = @record.send(association) 
     217          record.to_xml(opts.merge(:root => association)) 
     218        end 
     219      end 
     220    end 
     221 
    240222    def serialize 
    241223      args = [root] 
     
    243225        args << {:xmlns=>options[:namespace]} 
    244226      end 
    245        
     227 
    246228      if options[:type] 
    247229        args << {:type=>options[:type]} 
    248230      end 
    249          
     231 
    250232      builder.tag!(*args) do 
    251233        add_attributes 
    252         add_includes 
     234        add_includes { |association, records, opts| add_associations(association, records, opts) } 
    253235        add_procs 
    254236        yield builder if block_given? 
    255237      end 
    256     end         
     238    end 
    257239 
    258240    class Attribute #:nodoc: 
    259241      attr_reader :name, :value, :type 
    260      
     242 
    261243      def initialize(name, record) 
    262244        @name, @record = name, record 
    263        
     245 
    264246        @type  = compute_type 
    265247        @value = compute_value 
     
    278260        ![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type) 
    279261      end 
    280      
     262 
    281263      def decorations(include_types = true) 
    282264        decorations = {} 
     
    285267          decorations[:encoding] = 'base64' 
    286268        end 
    287        
     269 
    288270        if include_types && type != :string 
    289271          decorations[:type] = type 
    290272        end 
    291        
     273 
    292274        decorations 
    293275      end 
    294      
     276 
    295277      protected 
    296278        def compute_type 
     
    306288          end 
    307289        end 
    308      
     290 
    309291        def compute_value 
    310292          value = @record.send(name) 
    311          
     293 
    312294          if formatter = Hash::XML_FORMATTING[type.to_s] 
    313295            value ? formatter.call(value) : nil