Module: Ampere::Model

Defined in:
lib/ampere/model.rb

Overview

Including the ‘Ampere::Model` module into one of your classes mixes in all the class and instance methods of an Ampere model. See individual methods for more information.

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/ampere/model.rb', line 6

def self.included(base)
  base.extend(ClassMethods)
  
  base.extend(Keys)
  
  base.class_eval do
    extend(::ActiveModel::Callbacks)
    define_model_callbacks :create, :update, :save
    
    include(::ActiveModel::Validations)
    include(Rails.application.routes.url_helpers) if defined?(Rails)
    include(ActionController::UrlFor) if defined?(Rails)

    include(Ampere::Keys)
    
    attr_reader   :id
    attr_accessor :destroyed
    
    attr_accessor :fields
    attr_accessor :field_defaults
    attr_accessor :indices
    attr_accessor :field_types

    @fields         = []
    @field_defaults = {}
    @indices        = []
    @field_types    = {}
  end
end

Instance Method Details

#==(other) ⇒ Object

Compares this model with another one. If they are literally the same object or have been stored and have the same ID, then they are equal.



40
41
42
43
44
45
# File 'lib/ampere/model.rb', line 40

def ==(other)
  super or
    (other.instance_of?(self.class) and
    not id.nil? and
    other.id == id)
end

#attributesObject

Returns a Hash with all the fields and their values.



48
49
50
51
52
53
54
# File 'lib/ampere/model.rb', line 48

def attributes
  {:id => @id}.tap do |hash|
    self.class.fields.each do |key|
      hash[key] = self.send(key)
    end
  end
end

#destroyObject

Deletes this instance out of the database.



57
58
59
60
# File 'lib/ampere/model.rb', line 57

def destroy
  @destroyed = true
  self.class.delete(@id)
end

#destroyed?Boolean

Returns true if this record has been deleted

Returns:

  • (Boolean)


63
64
65
# File 'lib/ampere/model.rb', line 63

def destroyed?
  @destroyed
end

#eql?(other) ⇒ Boolean

Delegates to ==().

Returns:

  • (Boolean)


68
69
70
# File 'lib/ampere/model.rb', line 68

def eql?(other)
  self == other
end

#hashObject

Calculates the hash of this object from the attributes hash instead of using Object.hash.



74
75
76
# File 'lib/ampere/model.rb', line 74

def hash
  attributes.hash
end

#initialize(hash = {}, unmarshal = false) ⇒ Object

Initialize an instance like this:

Post.new :title => "Kitties: Are They Awesome?"


81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/ampere/model.rb', line 81

def initialize(hash = {}, unmarshal = false)
  @destroyed = false
  
  hash.each do |k, v|
    if k == 'id' then
      @id = unmarshal ? Marshal.load(v) : v
    elsif k =~ /_id$/
      self.send("#{k}=", v.to_i)
    else
      self.send("#{k}=", unmarshal ? Marshal.load(v) : v)
    end
  end
end

#new?Boolean Also known as: new_record?

Returns true if this record has not yet been saved.

Returns:

  • (Boolean)


96
97
98
# File 'lib/ampere/model.rb', line 96

def new?
  @id.nil? or not Ampere.connection.exists(key_for_find(self.class, @id))
end

#persisted?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/ampere/model.rb', line 101

def persisted?
  not @id.nil?
end

#reloadObject

Reloads this record from the database.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/ampere/model.rb', line 106

def reload
  if self.new? then
    raise "Can't reload a new record"
  end
  
  self.class.fields.each do |k|
    v = Ampere.connection.hget(key_for_find(self.class, @id), k)
    if k =~ /_id$/ then
      self.send("#{k}=", v.to_i)
    else
      self.send("#{k}=", Marshal.load(v))
    end
  end
  self
end

#saveObject

Saves this record to the database.



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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/ampere/model.rb', line 123

def save
  run_callbacks :save do
    run_callbacks :create do
      self.class.unique_indices.each do |idx|
        # For each uniquely-indexed field, look up the index for that field,
        # and throw an exception if this record's value for that field is in
        # the index already.
        if Ampere.connection.hexists(key_for_index(idx), instance_variable_get("@#{idx}")) then
          raise "Cannot save non-unique value for #{idx}"
        end
      end
      
      # Grab a fresh GUID from Redis by incrementing the "__guid" key
      if @id.nil? then
        @id = Ampere.connection.incr('__guid')
      end
      
      Ampere.connection.multi do
        self.attributes.each do |k, v|
          Ampere.connection.hset(key_for_find(self.class, @id), k, k =~ /_id$/ ? v : Marshal.dump(v))
        end
      end
      
      self.class.indices.each do |index|
        if index.class == String or index.class == Symbol then
          Ampere.connection.hset(
            key_for_index(index), 
            instance_variable_get("@#{index}"), 
            ([@id] | (Ampere.connection.hget(key_for_index(index), instance_variable_get("@#{index}")) or "")
            .split(/:/)).join(":")
          )
        elsif index.class == Array then
          key = index.map{|i| instance_variable_get("@#{i}")}.join(':')
          val = ([@id] | (Ampere.connection.hget(key_for_index(index), key) or "")
                .split(/:/)).join(":")
          Ampere.connection.hset(
            key_for_index(index.join(':')),
            key,
            val
          )
        end
      end
      self
    end
  end
end

#to_keyObject

:nodoc:



170
171
172
173
174
175
176
177
# File 'lib/ampere/model.rb', line 170

def to_key #:nodoc:
  # @id.nil? ? [] : [@id.to_i]
  if destroyed?
    [ @id.to_i ]
  else
    persisted? ? [ @id.to_i ] : nil
  end
end

#to_paramObject

:nodoc:



179
180
181
# File 'lib/ampere/model.rb', line 179

def to_param #:nodoc:
  @id.to_s
end

#update_attribute(key, value) ⇒ Object



183
184
185
186
187
# File 'lib/ampere/model.rb', line 183

def update_attribute(key, value)
  raise "Cannot update nonexistent field '#{key}'!" unless self.class.fields.include?(key.to_sym)
  self.send("#{key}=", value)
  Ampere.connection.hset(key_for_find(self.class, @id), key, Marshal.dump(value))
end

#update_attributes(hash = {}) ⇒ Object



189
190
191
192
193
194
195
196
197
198
# File 'lib/ampere/model.rb', line 189

def update_attributes(hash = {})
  # The efficient way, that I haven't figured out how to do yet:
  # Ampere.connection.hmset(@id, hash)
  
  # The inefficient way I know how to do right now:
  hash.each do |k, v|
    self.send("#{k}=", v)
  end
  self.save
end