@@ -4,49 +4,84 @@ module ActiveModel
44 class Serializer
55 class Adapter
66 class Json < Adapter
7- def serializable_hash ( options = nil )
7+ cattr_accessor :default_limit_depth , :default_check_depth_strategy
8+ self . default_limit_depth = 1
9+ self . default_check_depth_strategy = :trim
10+
11+ def serializable_hash options = nil
812 options ||= { }
9- if serializer . respond_to? ( :each )
10- @result = serializer . map { | s | FlattenJson . new ( s ) . serializable_hash ( options ) }
11- else
12- @hash = { }
13+ @current_depth = options [ :_current_depth ] || 0
14+ @without_root = options [ :_without_root ]
15+ @limit_depth = options [ :limit_depth ] || default_limit_depth
16+ @check_depth_strategy = options [ :check_depth_strategy ] || default_check_depth_strategy
1317
14- @core = cache_check ( serializer ) do
15- serializer . attributes ( options )
16- end
18+ @result =
19+ serialize_collection ( serializer , options . merge ( _without_root : true ) ) ||
20+ serialize_attributes ( options ) . merge ( serialize_associations )
21+ rooting? ? { root => @result } : @result
22+ end
23+
24+ def fragment_cache ( cached_hash , non_cached_hash )
25+ Json ::FragmentCache . new ( ) . fragment_cache ( cached_hash , non_cached_hash )
26+ end
27+
28+ private
29+
30+ def rooting?
31+ !@without_root && ( @current_depth == 0 )
32+ end
33+
34+ def serialize_object serializer , options = { }
35+ if serializer . try ( :object )
36+ self . class . new ( serializer ) . serializable_hash ( options )
37+ end
38+ end
1739
40+ def serialize_collection serializers , options = { }
41+ if serializers . respond_to? ( :each )
42+ serializers . map { |s | serialize_object ( s , options ) }
43+ end
44+ end
45+
46+ def serialize_attributes options
47+ cache_check ( serializer ) do
48+ serializer . attributes ( options )
49+ end
50+ end
51+
52+ def serialize_associations
53+ hash = { }
54+ next_depth = @current_depth + 1
55+ cascading_options = {
56+ limit_depth : @limit_depth ,
57+ check_depth_strategy : @check_depth_strategy ,
58+ _current_depth : next_depth
59+ }
60+ unless too_deep? next_depth
1861 serializer . associations . each do |association |
1962 serializer = association . serializer
20- opts = association . options
21-
22- if serializer . respond_to? ( :each )
23- array_serializer = serializer
24- @hash [ association . key ] = array_serializer . map do |item |
25- cache_check ( item ) do
26- item . attributes ( opts )
27- end
28- end
29- else
30- @hash [ association . key ] =
31- if serializer && serializer . object
32- cache_check ( serializer ) do
33- serializer . attributes ( options )
34- end
35- elsif opts [ :virtual_value ]
36- opts [ :virtual_value ]
37- end
38- end
63+ opts = association . options . merge ( cascading_options )
64+ hash [ association . key ] =
65+ serialize_collection ( serializer , opts ) ||
66+ serialize_object ( serializer , opts ) ||
67+ opts [ :virtual_value ]
3968 end
40- @result = @core . merge @hash
4169 end
42-
43- { root => @result }
70+ hash
4471 end
4572
46- def fragment_cache ( cached_hash , non_cached_hash )
47- Json ::FragmentCache . new ( ) . fragment_cache ( cached_hash , non_cached_hash )
73+ def too_deep? depth
74+ if depth > @limit_depth
75+ case @check_depth_strategy
76+ when :fail
77+ fail 'Too deep associations.'
78+ when :trim
79+ true
80+ end
81+ else
82+ false
83+ end
4884 end
49-
5085 end
5186 end
5287 end
0 commit comments