Class: Mongoid::Tracking::Tracker

Inherits:
Object
  • Object
show all
Includes:
Readers
Defined in:
lib/mongoid/tracking/tracker.rb

Overview

This internal class handles all interaction for a track field.

Instance Method Summary collapse

Methods included from Readers

#all_values, #date_cleanup, #first_date, #first_value, #last_date, #last_days, #last_value, #on, #today, #yesterday

Constructor Details

#initialize(owner, field, aggregate_data) ⇒ Tracker

Returns a new instance of Tracker.



9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/mongoid/tracking/tracker.rb', line 9

def initialize(owner, field, aggregate_data)
  @owner, @for = owner, field
  @for_data = @owner.internal_track_name(@for)
  @data = @owner.read_attribute(@for_data)

  if @data.nil?
    @owner.write_attribute(@for_data, {})
    @data = @owner.read_attribute(@for_data)
  end

  @aggregate_data = aggregate_data.first if aggregate_data.first
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Object

Delegate all missing methods to the aggregate accessors. This enables us to call an aggregation token after the tracking field.

Example:

<tt>@object.visits.browsers ...</tt>


29
30
31
32
# File 'lib/mongoid/tracking/tracker.rb', line 29

def method_missing(name, *args, &block)
  super unless @owner.aggregate_fields.member?(name)
  @owner.send("#{name}_with_track".to_sym, @for, *args, &block)
end

Instance Method Details

#add(how_much = 1, date = Time.now) ⇒ Object

Update methods



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/mongoid/tracking/tracker.rb', line 35

def add(how_much = 1, date = Time.now)
  raise Errors::ModelNotSaved, "Can't update a new record. Save first!" if @owner.new_record?
  return if how_much == 0

  # Note that the following #update_data method updates our local data
  # and the current value might differ from the actual value on the
  # database. Basically, what we do is update our own copy as a cache
  # but send the command to atomically update the database: we don't
  # read the actual value in return so that we save round trip delays.
  #
  update_data(data_for(date) + how_much, date)
  @owner.inc(store_key(date), how_much.abs)

  return unless @owner.aggregated?

  @owner.aggregate_fields.each do |k, v|
    next unless token = v.call(@aggregate_data)
    fk = @owner.class.name.to_s.foreign_key.to_sym
    selector = { fk => @owner.id, ns: k, key: token.to_s }

    docs = @owner.aggregate_klass.collection.find(selector)
    docs.upsert("$inc" => update_hash(how_much.abs, date))
  end
end

#dec(date = Time.now) ⇒ Object



64
65
66
# File 'lib/mongoid/tracking/tracker.rb', line 64

def dec(date = Time.now)
  add(-1, date)
end

#erase(date = Time.now) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/mongoid/tracking/tracker.rb', line 103

def erase(date = Time.now)
  raise Errors::ModelNotSaved, "Can't update a new record" if @owner.new_record?

  remove_data(date)

  @owner.unset(store_key(date))

  return unless @owner.aggregated?

  # Need to iterate over all aggregates and send an update or delete
  # operations over all mongo records
  @owner.aggregate_fields.each do |(k,v)|
    fk = @owner.class.name.to_s.foreign_key.to_sym
    selector = { fk => @owner.id, ns: k }

    docs = @owner.aggregate_klass.collection.find(selector)
    docs.update_all("$unset" => update_hash(1, date))
  end
end

#inc(date = Time.now) ⇒ Object



60
61
62
# File 'lib/mongoid/tracking/tracker.rb', line 60

def inc(date = Time.now)
  add(1, date)
end

#reset(how_much, date = Time.now) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/mongoid/tracking/tracker.rb', line 86

def reset(how_much, date = Time.now)
  return erase(date) if how_much.nil?

  # First, we use the default "set" for the tracking field
  # This will also update one aggregate but... oh well...
  set(how_much, date)

  # Need to iterate over all aggregates and send an update or delete
  # operations over all mongo records for this aggregate field
  @owner.aggregate_fields.each do |(k,v)|
    fk = @owner.class.name.to_s.foreign_key.to_sym
    selector = { fk => @owner.id, ns: k }
    docs = @owner.aggregate_klass.collection.find(selector)
    docs.update_all("$set" => update_hash(how_much.abs, date))
  end
end

#set(how_much, date = Time.now) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/mongoid/tracking/tracker.rb', line 68

def set(how_much, date = Time.now)
  raise Errors::ModelNotSaved, "Can't update a new record" if @owner.new_record?
  update_data(how_much, date)

  @owner.set(store_key(date), how_much)

  return unless @owner.aggregated?

  @owner.aggregate_fields.each do |(k,v)|
    next unless token = v.call(@aggregate_data)
    fk = @owner.class.name.to_s.foreign_key.to_sym
    selector = { fk => @owner.id, ns: k, key: token.to_s }

    docs = @owner.aggregate_klass.collection.find(selector)
    docs.upsert("$set" => update_hash(how_much.abs, date))
  end
end