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

root/tags/rel_2-0-2/activerecord/lib/active_record/serialization.rb

Revision 7663, 3.5 kB (checked in by david, 1 year ago)

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

Line 
1 module ActiveRecord #:nodoc:
2   module Serialization
3     class Serializer #:nodoc:
4       attr_reader :options
5
6       def initialize(record, options = {})
7         @record, @options = record, options.dup
8       end
9
10       # To replicate the behavior in ActiveRecord#attributes,
11       # :except takes precedence over :only.  If :only is not set
12       # for a N level model but is set for the N+1 level models,
13       # then because :except is set to a default value, the second
14       # level model can have both :except and :only set.  So if
15       # :only is set, always delete :except.
16       def serializable_attribute_names
17         attribute_names = @record.attribute_names
18
19         if options[:only]
20           options.delete(:except)
21           attribute_names = attribute_names & Array(options[:only]).collect { |n| n.to_s }
22         else
23           options[:except] = Array(options[:except]) | Array(@record.class.inheritance_column)
24           attribute_names = attribute_names - options[:except].collect { |n| n.to_s }
25         end
26
27         attribute_names
28       end
29
30       def serializable_method_names
31         Array(options[:methods]).inject([]) do |method_attributes, name|
32           method_attributes << name if @record.respond_to?(name.to_s)
33           method_attributes
34         end
35       end
36
37       def serializable_names
38         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
71       end
72
73       def serializable_record
74         returning(serializable_record = {}) do
75           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
83         end
84       end
85
86       def serialize
87         # overwrite to implement
88       end
89
90       def to_s(&block)
91         serialize(&block)
92       end
93     end
94   end
95 end
96
97 require 'active_record/serializers/xml_serializer'
98 require 'active_record/serializers/json_serializer'
Note: See TracBrowser for help on using the browser.