module Ampere::Model

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.

Public Class Methods

included(base) click to toggle source
# 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
new(hash = {}, unmarshal = false) click to toggle source

Initialize an instance like this:

Post.new :title => "Kitties: Are They Awesome?"
# 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

Public Instance Methods

==(other) click to toggle source

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.

Calls superclass method
# 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
attributes() click to toggle source

Returns a Hash with all the fields and their values.

# 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
destroy() click to toggle source

Deletes this instance out of the database.

# File lib/ampere/model.rb, line 57
def destroy
  @destroyed = true
  self.class.delete(@id)
end
destroyed?() click to toggle source

Returns true if this record has been deleted

# File lib/ampere/model.rb, line 63
def destroyed?
  @destroyed
end
eql?(other) click to toggle source

Delegates to ==().

# File lib/ampere/model.rb, line 68
def eql?(other)
  self == other
end
hash() click to toggle source

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

# File lib/ampere/model.rb, line 74
def hash
  attributes.hash
end
new?() click to toggle source

Returns true if this record has not yet been saved.

# File lib/ampere/model.rb, line 96
def new?
  @id.nil? or not Ampere.connection.exists(key_for_find(self.class, @id))
end
Also aliased as: new_record?
new_record?()
Alias for: new?
persisted?() click to toggle source
# File lib/ampere/model.rb, line 101
def persisted?
  not @id.nil?
end
reload() click to toggle source

Reloads this record from the database.

# 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
save() click to toggle source

Saves this record to the database.

# 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
update_attribute(key, value) click to toggle source
# 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 = {}) click to toggle source
# 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