Module: Mongoid::CachedJson::ClassMethods

Defined in:
lib/mongoid-cached-json/cached_json.rb

Instance Method Summary collapse

Instance Method Details

#cached_json_key(options, cached_class, cached_id) ⇒ Object

Cache key.



109
110
111
112
# File 'lib/mongoid-cached-json/cached_json.rb', line 109

def cached_json_key(options, cached_class, cached_id)
  base_class_name = cached_class.collection_name.to_s.singularize.camelize
  "as_json/#{options[:version]}/#{base_class_name}/#{cached_id}/#{options[:properties]}/#{!!options[:is_top_level_json]}"
end

#json_fields(defs) ⇒ Object

Define JSON fields for a class.

Parameters:

  • defs (hash)

    JSON field definition.

Since:

  • 1.0



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/mongoid-cached-json/cached_json.rb', line 21

def json_fields(defs)
  self.hide_as_child_json_when = defs.delete(:hide_as_child_json_when) || lambda { |a| false }
  self.all_json_properties = [ :short, :public, :all ]
  cached_json_defs = Hash[defs.map { |k,v| [k, { :type => :callable, :properties => :short, :definition => k }.merge(v)] }]
  self.cached_json_field_defs = {}
  self.cached_json_reference_defs = {}
  # Collect all versions for clearing cache
  self.all_json_versions = cached_json_defs.map do |field, definition|
    [ :unspecified, definition[:version], Array(definition[:versions]) ]
  end.flatten.compact.uniq
  self.all_json_properties.each_with_index do |property, i|
    self.cached_json_field_defs[property] = Hash[cached_json_defs.find_all do |field, definition|
      self.all_json_properties.find_index(definition[:properties]) <= i && definition[:type] == :callable
    end]
    self.cached_json_reference_defs[property] = Hash[cached_json_defs.find_all do |field, definition|
      self.all_json_properties.find_index(definition[:properties]) <= i && definition[:type] == :reference
    end]
    # If the field is a reference and is just specified as a symbol, reflect on it to get metadata
    self.cached_json_reference_defs[property].to_a.each do |field, definition|
      if definition[:definition].is_a?(Symbol)
        self.cached_json_reference_defs[property][field][:metadata] = self.reflect_on_association(definition[:definition])
      end
    end
  end
  after_update :expire_cached_json
  after_destroy :expire_cached_json
end

#materialize_cached_json(clazz, id, object_reference, options) ⇒ Object

Materialize a cached JSON within a cache block.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/mongoid-cached-json/cached_json.rb', line 50

def materialize_cached_json(clazz, id, object_reference, options)
  is_top_level_json = options[:is_top_level_json] || false
  object_reference = clazz.where({ :_id => id }).first if !object_reference
  if !object_reference || (!is_top_level_json && options[:properties] != :all && clazz.hide_as_child_json_when.call(object_reference))
    nil
  else
    Hash[clazz.cached_json_field_defs[options[:properties]].map do |field, definition|
      # version match
      versions = ([definition[:version] ] | Array(definition[:versions])).compact
      next unless versions.empty? or versions.include?(options[:version])
      json_value = (definition[:definition].is_a?(Symbol) ? object_reference.send(definition[:definition]) : definition[:definition].call(object_reference))
      Mongoid::CachedJson.config.transform.each do |t|
        json_value = t.call(field, definition, json_value)
      end
      [field, json_value]
    end]
  end
end

#materialize_json(options, object_def) ⇒ Object

Given an object definition in the form of either an object or a class, id pair, grab the as_json representation from the cache if possible, otherwise create the as_json representation by loading the object from the database. For any references in the object’s JSON representation, we have to recursively materialize the JSON by calling resolve_json_reference on each of them (which may, in turn, call materialize_json)



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/mongoid-cached-json/cached_json.rb', line 75

def materialize_json(options, object_def)
  return nil if !object_def[:object] and !object_def[:id]
  is_top_level_json = options[:is_top_level_json] || false
  if object_def[:object]
    object_reference = object_def[:object]
    clazz, id = object_def[:object].class, object_def[:object].id
  else
    object_reference = nil
    clazz, id = object_def[:clazz], object_def[:id]
  end
  key = self.cached_json_key(options, clazz, id)
  json = { :_ref => { :_clazz => self, :_key => key, :_materialize_cached_json => [ clazz, id, object_reference, options ] }}
  keys = KeyReferences.new
  keys.set_and_add(key, json)
  reference_defs = clazz.cached_json_reference_defs[options[:properties]]
  if !reference_defs.empty?
    object_reference = clazz.where({ :_id => id }).first if !object_reference
    if object_reference && (is_top_level_json || options[:properties] == :all || !clazz.hide_as_child_json_when.call(object_reference))
      json.merge!(Hash[reference_defs.map do |field, definition|
        json_properties_type = definition[:reference_properties] || ((options[:properties] == :all) ? :all : :short)
        reference_keys, reference = clazz.resolve_json_reference(options.merge({ :properties => json_properties_type, :is_top_level_json => false}), object_reference, field, definition)
        if (reference.is_a?(Hash) && ref = reference[:_ref])
          ref[:_parent] = json
          ref[:_field] = field
        end
        keys.merge_set(reference_keys)
        [field, reference]
      end])
    end
  end
  [ keys, json ]
end

#resolve_json_reference(options, object, field, reference_def) ⇒ Object

If the reference is a symbol, we may be lucky and be able to figure out the as_json representation by the (class, id) pair definition of the reference. That is, we may be able to load the as_json representation from the cache without even getting the model from the database and materializing it through Mongoid. We’ll try to do this first.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/mongoid-cached-json/cached_json.rb', line 118

def resolve_json_reference(options, object, field, reference_def)
  keys = nil
  reference_json = nil
  if reference_def[:metadata]
    key = reference_def[:metadata].key.to_sym
    if reference_def[:metadata].polymorphic?
      clazz = reference_def[:metadata].inverse_class_name.constantize
    else
      clazz = reference_def[:metadata].class_name.constantize
    end
    if reference_def[:metadata].relation == Mongoid::Relations::Referenced::ManyToMany
      object_ids = object.send(key)
      reference_json = object_ids ? object_ids.map do |id|
        materialize_keys, json = materialize_json(options, { :clazz => clazz, :id => id })
        keys = keys ? keys.merge_set(materialize_keys) : materialize_keys
        json
      end.compact : []
    end
  end
  # If we get to this point and reference_json is still nil, there's no chance we can
  # load the JSON from cache so we go ahead and call as_json on the object.
  if ! reference_json
    reference_def_definition = reference_def[:definition]
    reference = reference_def_definition.is_a?(Symbol) ? object.send(reference_def_definition) : reference_def_definition.call(object)
    reference_json = nil
    if reference
      if reference.respond_to?(:as_json_partial)
        reference_keys, reference_json = reference.as_json_partial(options)
        keys = keys ? keys.merge_set(reference_keys) : reference_keys
      else
        reference_json = reference.as_json(options)
      end
    end
  end
  [ keys, reference_json ]
end