Class: SuperAwesomeResourceSerializer

Inherits:
Object
  • Object
show all
Defined in:
lib/super_awesome_resource_serializer.rb

Overview

This class provides the base functionality for serializing Activeobject objects to XML, JSON, or YAML. It is intended to be used with web services where tighter control is desired than is provided by ActiveResource out of the box. For instance, you may have some sensitive fields in your Activeobject that should not be made available through a public web service API unless the user is a trusted user.

To create a serializer for you model, you simply need to make a new class named ModelNameSerializer where ModelName is the class name of your model. The serializer class itself then needs to define how each field should be serialized using the serialize method.

Defined Under Namespace

Classes: SerializedFieldInfo

Constant Summary collapse

STATIC_CLASSES =
[String, Symbol, Fixnum, Float, NilClass, TrueClass, FalseClass, Object].inject({}){|hash, klass| hash[klass] = true; hash}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(object, serialize_options = {}) ⇒ SuperAwesomeResourceSerializer

Create a new serializer. Options can be passed in for :exclude, :include, or :only to determine which fields will be used.

To indicate a field should be included or excluded on a serializer returned by a field, prefix it with the field name. For example, if you have a field :venue and this field returns a VenueSerializer object and you only want the id of the venue, you can specify :only => “venue.id”.



161
162
163
164
165
166
167
# File 'lib/super_awesome_resource_serializer.rb', line 161

def initialize (object, serialize_options = {})
  @object = object
  @include_fields = self.class.normalize_field_list(serialize_options[:include])
  @exclude_fields = self.class.normalize_field_list(serialize_options[:exclude])
  @only_fields = self.class.normalize_field_list(serialize_options[:only])
  @root_element = serialize_options[:root_element] ? serialize_options[:root_element].to_s : object.class.name.underscore.gsub("/", "-")
end

Instance Attribute Details

#exclude_fieldsObject (readonly)

Returns the value of attribute exclude_fields.



153
154
155
# File 'lib/super_awesome_resource_serializer.rb', line 153

def exclude_fields
  @exclude_fields
end

#include_fieldsObject (readonly)

Returns the value of attribute include_fields.



153
154
155
# File 'lib/super_awesome_resource_serializer.rb', line 153

def include_fields
  @include_fields
end

#objectObject (readonly)

Returns the value of attribute object.



153
154
155
# File 'lib/super_awesome_resource_serializer.rb', line 153

def object
  @object
end

#only_fieldsObject (readonly)

Returns the value of attribute only_fields.



153
154
155
# File 'lib/super_awesome_resource_serializer.rb', line 153

def only_fields
  @only_fields
end

#root_elementObject (readonly)

Returns the value of attribute root_element.



153
154
155
# File 'lib/super_awesome_resource_serializer.rb', line 153

def root_element
  @root_element
end

Class Method Details

.for_object(object, options = {}, klass = object.class) ⇒ Object

Get the serializer class for a given object.



19
20
21
22
23
24
25
26
27
28
# File 'lib/super_awesome_resource_serializer.rb', line 19

def for_object (object, options = {}, klass = object.class)
  serializer_class = "#{klass.name}Serializer".constantize
  return serializer_class.new(object, options)
rescue
  if klass.superclass.nil?
    raise NameError.new("no known serializers for class #{object.class.name}")
  else
    return for_object(object, options, klass.superclass)
  end
end

.merge_field_lists(list_1, list_2) ⇒ Object

Merge the values of two field lists as used in :include, :exclude, and :only options.



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/super_awesome_resource_serializer.rb', line 44

def merge_field_lists (list_1, list_2)
  if list_1.blank?
    if list_2.blank?
      return nil
    else
      return list_2
    end
  elsif list_2.blank?
    return list_1
  else
    list_1 = normalize_field_list(list_1)
    list_2 = normalize_field_list(list_2)
    merge_hashes(list_1, list_2)
  end
end

.normalize_field_list(field_list) ⇒ Object

Turn an :include, :exclude, or :only field list into a hash for consistent access.



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/super_awesome_resource_serializer.rb', line 61

def normalize_field_list (field_list)
  case field_list
  when nil
    return {}
  when true
    return {}
  when String
    return {field_list.to_sym => true}
  when Symbol
    return {field_list => true}
  when Array
    hash = {}
    field_list.each do |value|
      if value.is_a?(Hash)
        hash.merge!(normalize_field_list(value))
      else
        hash[value.to_sym] = true
      end
    end
    return hash
  when Hash
    hash = {}
    field_list.each_pair do |key, value|
      value = normalize_field_list(value) unless value == true
      hash[key.to_sym] = value
    end
    return hash
  else
    raise ArgumentError.new("illegal type in field list: #{field_list.class.name}")
  end
end

.param_keyObject

Get the field name with the unique key used to lookup the object



120
121
122
123
124
125
126
127
128
# File 'lib/super_awesome_resource_serializer.rb', line 120

def param_key
  if @param_key
    @param_key
  elsif superclass < SuperAwesomeResourceSerializer
    superclass.param_key
  else
    :id
  end
end

.param_key=(val) ⇒ Object

Set the field name with the unique key used to lookup the object



131
132
133
# File 'lib/super_awesome_resource_serializer.rb', line 131

def param_key= (val)
  @param_key = val
end

.serializable_fields(action, options = {}) ⇒ Object

Get a list of serialized field information for preforming an action (either :getter or :setter) on the class. Option can pass in values for :include, :exclude, and :only to indicate filters on what fields are allowed. Include can be used to add fields that have been defined but excluded by default, exclude can be used to remove fields included by default, while only is used to specify the exact list of fields to use.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/super_awesome_resource_serializer.rb', line 97

def serializable_fields (action, options = {})
  if self == SuperAwesomeResourceSerializer
    return []
  else
    exclude_fields = options[:exclude] || {}
    include_fields = options[:include] || {}
    only_fields = options[:only] || {}

    all_field_info = superclass.serializable_fields(options) + serialized_field_info

    if only_fields.empty?
      excluded_field_names = exclude_fields.collect{|k,v| k if v == true}.compact
      excluded_field_names = (excluded_field_names + all_field_info.select{|field| field.excluded?(action)}.collect{|field| field.name}) - include_fields.keys
      all_field_info.delete_if{|field| excluded_field_names.include?(field.name)} unless excluded_field_names.empty?
    else
      all_field_info.delete_if{|field| not only_fields.include?(field.name)}
    end

    return all_field_info
  end
end

.serialize(field, options = {}) ⇒ Object

Define how to serialize and deserialize a field. The following options can be passed in to define how to serialize an object.

  • :element - The name of the field in the serialized output. This can be used to give a object a prettier name on output.

  • :getter - The getter to get the field value.

  • :setter - The setter to set the field value.

  • :exclude - Indicate that this field should be excluded unless specifically asked for. Values can be :getter, :setter, or true.

By default, getters and setters will call the field accessor on the serializer (if it is defined) or on the object. This can be overridden by specifying a different method name to call, or a proc that will be yielded to with the object (and value for a setter). Finally, getters and setters can be disabled by setting them to false.



39
40
41
# File 'lib/super_awesome_resource_serializer.rb', line 39

def serialize (field, options = {})
  serialized_field_info << SerializedFieldInfo.new(field, options)
end

Instance Method Details

#==(val) ⇒ Object



227
228
229
# File 'lib/super_awesome_resource_serializer.rb', line 227

def == (val)
  return val.is_a?(self.class) && val.object == object && val.include_fields == include_fields && val.exclude_fields == exclude_fields && val.only_fields == only_fields && val.root_element == root_element
end

#set_attributes(attributes) ⇒ Object

Set the attributes on the underlying object by calling the available setters. All keys in the hash (and in any hashes in the values) will be converted to symbols.



171
172
173
174
175
176
177
178
179
# File 'lib/super_awesome_resource_serializer.rb', line 171

def set_attributes (attributes)
  return unless attributes
  attributes = normalize_attribute_keys(attributes)
  serializable_fields(:setter).each do |field|
    if attributes.include?(field.name)
      field.set(self, attributes[field.name])
    end
  end
end

#to_hashObject

Serialize the object to a hash.



197
198
199
200
201
202
203
204
205
# File 'lib/super_awesome_resource_serializer.rb', line 197

def to_hash
  hash = HashWithIndifferentAccess.new
  serializable_fields(:getter).each do |field|
    if field.getter?
      hash[field.element] = wrap_object_for_hash(field.get(self), field.name)
    end
  end
  return hash
end

#to_json(json_options = nil) ⇒ Object

Serialize the object to JSON.



213
214
215
# File 'lib/super_awesome_resource_serializer.rb', line 213

def to_json (json_options = nil)
  to_hash.to_json(json_options)
end

#to_paramObject

Get the unique key used for lookups



223
224
225
# File 'lib/super_awesome_resource_serializer.rb', line 223

def to_param
  object.send(self.class.param_key || :id)
end

#to_xml(xml_options = {}) ⇒ Object

Serialize the object to XML.



208
209
210
# File 'lib/super_awesome_resource_serializer.rb', line 208

def to_xml (xml_options = {})
  to_hash.to_xml({:root => root_element, :dasherize => false}.reverse_merge(xml_options))
end

#to_yaml(yaml_options = {}) ⇒ Object

Serialize the object to YAML.



218
219
220
# File 'lib/super_awesome_resource_serializer.rb', line 218

def to_yaml (yaml_options = {})
  remove_hash_indifferent_access(to_hash).to_yaml(yaml_options)
end

#update_with_json(json) ⇒ Object

Update the available fields in the object with a serialized representation of the object in JSON.



187
188
189
# File 'lib/super_awesome_resource_serializer.rb', line 187

def update_with_json (json)
  set_attributes(ActiveSupport::JSON.decode(json))
end

#update_with_xml(xml) ⇒ Object

Update the available fields in the object with a serialized representation of the object in XML.



182
183
184
# File 'lib/super_awesome_resource_serializer.rb', line 182

def update_with_xml (xml)
  set_attributes(Hash.from_xml(xml)[root_element])
end

#update_with_yaml(yaml) ⇒ Object

Update the available fields in the object with a serialized representation of the object in YAML.



192
193
194
# File 'lib/super_awesome_resource_serializer.rb', line 192

def update_with_yaml (yaml)
  set_attributes(YAML.load(yaml))
end