module AWS::Record::AbstractBase::InstanceMethods

Public Class Methods

new(attributes = {}) click to toggle source

Constructs a new record.

@param [Hash] attributes Attributes that should be bulk assigned

to this record.  You can also specify the shard (i.e. domain
or table) this record should persist to via `:shard`).

@option attributes [String] :shard The domain/table this record

should persist to.  If this is omitted, it will persist to the
class default shard (which defaults to the class name).

@return [Model,HashModel] Returns a new (non-persisted) record.

Call {#save} to persist changes to AWS.
# File lib/aws/record/abstract_base.rb, line 50
def initialize attributes = {}

  attributes = attributes.dup

  # supporting :domain for backwards compatability, :shard is prefered
  @_shard = attributes.delete(:domain)
  @_shard ||= attributes.delete('domain')
  @_shard ||= attributes.delete(:shard)
  @_shard ||= attributes.delete('shard')
  @_shard = self.class.shard_name(@_shard)

  @_data = {}
  assign_default_values
  bulk_assign(attributes)

end

Public Instance Methods

attributes() click to toggle source

@return [Hash] A hash with attribute names as hash keys (strings) and

attribute values (of mixed types) as hash values.
# File lib/aws/record/abstract_base.rb, line 77
def attributes
  attributes = Core::IndifferentHash.new
  self.class.attributes.keys.inject(attributes) do |hash,attr_name|
    hash.merge(attr_name => __send__(attr_name))
  end
end
attributes=(attributes) click to toggle source

Acts like {#update} but does not call {#save}.

record.attributes = { :name => 'abc', :age => 20 }

@param [Hash] attributes A hash of attributes to set on this record

without calling save.

@return [Hash] Returns the attribute hash that was passed in.

# File lib/aws/record/abstract_base.rb, line 93
def attributes= attributes
  bulk_assign(attributes)
end
delete() click to toggle source

Deletes the record. @return [true]

# File lib/aws/record/abstract_base.rb, line 177
def delete
  if persisted?
    if deleted?
      raise 'unable to delete, this object has already been deleted'
    else
      delete_storage
      @_deleted = true
    end
  else
    raise 'unable to delete, this object has not been saved yet'
  end
end
Also aliased as: destroy
deleted?() click to toggle source

@return [Boolean] Returns true if this instance object has been deleted.

# File lib/aws/record/abstract_base.rb, line 192
def deleted?
  persisted? ? !!@_deleted : false
end
destroy()
Alias for: delete
domain()
Alias for: shard
errors() click to toggle source
# File lib/aws/record/abstract_base.rb, line 125
def errors
  @errors ||= Errors.new
end
new_record?() click to toggle source

@return [Boolean] Returns true if this record has not been persisted

to SimpleDB.
# File lib/aws/record/abstract_base.rb, line 112
def new_record?
  !persisted?
end
persisted?() click to toggle source

Persistence indicates if the record has been saved previously or not.

@example

@recipe = Recipe.new(:name => 'Buttermilk Pancackes')
@recipe.persisted? #=> false
@recipe.save!
@recipe.persisted? #=> true

@return [Boolean] Returns true if this record has been persisted.

# File lib/aws/record/abstract_base.rb, line 106
def persisted?
  !!@_persisted
end
save(opts = {}) click to toggle source

Creates new records, updates existing records. @param [Hash] opts Pass :validate => false to skip validations @return [Boolean] Returns true if the record saved without errors,

false otherwise.
# File lib/aws/record/abstract_base.rb, line 133
def save opts = {}
  if valid?(opts)
    persisted? ? update : create
    clear_changes!
    true
  else
    false
  end
end
save!() click to toggle source

Creates new records, updates exsting records. If there is a validation error then an exception is raised. @raise [InvalidRecordError] Raised when the record has validation

errors and can not be saved.

@return [true] Returns true after a successful save.

# File lib/aws/record/abstract_base.rb, line 148
def save!
  raise InvalidRecordError.new(self) unless save
  true
end
shard() click to toggle source

@return [String] Returns the name of the shard this record

is persisted to or will be persisted to.  Defaults to the
domain/table named after this record class.
# File lib/aws/record/abstract_base.rb, line 70
def shard
  @_shard
end
Also aliased as: domain
update_attributes(attribute_hash) click to toggle source

Bulk assigns the attributes and then saves the record. @param [Hash] attribute_hash A hash of attribute names (keys) and

attribute values to assign to this record.

@return (see save)

# File lib/aws/record/abstract_base.rb, line 157
def update_attributes attribute_hash
  bulk_assign(attribute_hash)
  save
end
update_attributes!(attribute_hash) click to toggle source

Bulk assigns the attributes and then saves the record. Raises an exception (AWS::Record::InvalidRecordError) if the record is not valid. @param (see update_attributes) @return [true]

# File lib/aws/record/abstract_base.rb, line 167
def update_attributes! attribute_hash
  if update_attributes(attribute_hash)
    true
  else
    raise InvalidRecordError.new(self)
  end
end
valid?(opts = {}) click to toggle source

@param [Hash] opts Pass :validate => false to skip validations @return [Boolean] Returns true if this record has no validation errors.

# File lib/aws/record/abstract_base.rb, line 118
def valid? opts = {}
  opts = {} if opts.nil?
  opts = {:validate => true}.merge(opts)
  run_validations if opts[:validate]
  errors.empty?
end

Protected Instance Methods

[](attribute_name) click to toggle source

Returns the typecasted value for the named attribute.

book = Book.new(:title => 'My Book')
book['title'] #=> 'My Book'
book.title    #=> 'My Book'

### Intended Use

This method's primary use is for getting/setting the value for an attribute inside a custom method:

class Book < AWS::Record::Model

  string_attr :title

  def title
    self['title'] ? self['title'].upcase : nil
  end

end

book = Book.new(:title => 'My Book')
book.title    #=> 'MY BOOK'

@param [String,Symbol] attribute_name The name of the attribute to fetch

a value for.

@return The current type-casted value for the named attribute.

# File lib/aws/record/abstract_base.rb, line 259
def [] attribute_name
  self.class.attribute_for(attribute_name) do |attribute|
    type_cast(attribute, @_data[attribute.name])
  end
end
[]=(attribute_name, new_value) click to toggle source

If you define a custom setter, you use #[]= to set the value on the record.

class Book < AWS::Record::Model

  string_attr :name

  # replace the default #author= method
  def author= name
    self['author'] = name.blank? ? 'Anonymous' : name
  end

end

@param [String,Symbol] The attribute name to set a value for @param attribute_value The value to assign.

# File lib/aws/record/abstract_base.rb, line 213
def []= attribute_name, new_value
  self.class.attribute_for(attribute_name) do |attribute|

    if_tracking_changes do
      original_value = type_cast(attribute, attribute_was(attribute.name))
      incoming_value = type_cast(attribute, new_value)
      if original_value == incoming_value
        clear_change!(attribute.name)
      else
        attribute_will_change!(attribute.name)
      end
    end

    @_data[attribute.name] = new_value

  end
end
create() click to toggle source
# File lib/aws/record/abstract_base.rb, line 266
def create
  populate_id
  touch_timestamps('created_at', 'updated_at')
  increment_optimistic_lock_value
  create_storage
  @_persisted = true
end
create_storage() click to toggle source
# File lib/aws/record/abstract_base.rb, line 456
def create_storage
  raise NotImplementedError
end
delete_storage() click to toggle source
# File lib/aws/record/abstract_base.rb, line 466
def delete_storage
  raise NotImplementedError
end
hydrate(id, data) click to toggle source

@api private

# File lib/aws/record/abstract_base.rb, line 440
def hydrate id, data
  # New objects are populated with default values, but we don't
  # want these values to hang around when hydrating persisted values
  # (those values may have been blanked out before save).
  self.class.attributes.values.each do |attribute|
    @_data[attribute.name] = nil
  end

  ignore_changes do
    bulk_assign(deserialize_item_data(data))
  end

  @_persisted = true
end
if_locks_optimistically() { |opt_lock_attr| ... } click to toggle source
# File lib/aws/record/abstract_base.rb, line 308
def if_locks_optimistically &block
  if opt_lock_attr = self.class.optimistic_locking_attr
    yield(opt_lock_attr)
  end
end
increment_optimistic_lock_value() click to toggle source
# File lib/aws/record/abstract_base.rb, line 297
def increment_optimistic_lock_value
  if_locks_optimistically do |lock_attr|
    if value = self[lock_attr.name]
      self[lock_attr.name] = value + 1
    else
      self[lock_attr.name] = 1
    end
  end
end
opt_lock_conditions() click to toggle source
# File lib/aws/record/abstract_base.rb, line 315
def opt_lock_conditions
  conditions = {}
  if_locks_optimistically do |lock_attr|
    if was = attribute_was(lock_attr.name)
      conditions[:if] = { lock_attr.name => lock_attr.serialize(was) }
    else
      conditions[:unless_exists] = lock_attr.name
    end
  end
  conditions
end
touch_timestamps(*attributes) click to toggle source
# File lib/aws/record/abstract_base.rb, line 283
def touch_timestamps *attributes
  now = Time.now
  attributes.each do |attr_name|
    if
      self.class.attributes[attr_name] and
      !attribute_changed?(attr_name)
      # don't touch timestamps the user modified
    then
      __send__("#{attr_name}=", now)
    end
  end
end
update_storage() click to toggle source
# File lib/aws/record/abstract_base.rb, line 461
def update_storage
  raise NotImplementedError
end

Private Instance Methods

assign_default_values() click to toggle source
# File lib/aws/record/abstract_base.rb, line 328
def assign_default_values
  # populate default attribute values
  ignore_changes do
    self.class.attributes.values.each do |attribute|
      default = attribute.default_value
      begin
        # copy default values down so methods like #gsub! don't
        # modify the default values for other objects
        @_data[attribute.name] = default.clone
      rescue TypeError
        @_data[attribute.name] = default
      end
    end
  end
end
bulk_assign(hash) click to toggle source
# File lib/aws/record/abstract_base.rb, line 345
def bulk_assign hash
  flatten_date_parts(hash).each_pair do |attr_name, attr_value|
    __send__("#{attr_name}=", attr_value)
  end
end
flatten_date_parts(attributes) click to toggle source

Rails date and time select helpers split date and time attributes into multiple values for form submission. These attributes get named things like 'created_at(1i)' and represent year/month/day/hour/min/sec parts of the date/time.

This method converts these attributes back into a single value and converts them to Date and DateTime objects.

# File lib/aws/record/abstract_base.rb, line 360
def flatten_date_parts attributes

  multi_attributes = Set.new

  hash = attributes.inject({}) do |hash,(key,value)|
    # collects attribuets like "created_at(1i)" into an array of parts
    if key =~ /\(/
      key, index = key.to_s.split(/\(|i\)/)
      hash[key] ||= []
      hash[key][index.to_i - 1] = value.to_i
      multi_attributes << key
    else
      hash[key] = value
    end
    hash
  end

  # convert multiattribute values into date/time objects
  multi_attributes.each do |key|

    values = hash[key]

    hash[key] = case values.size
    when 0 then nil
    when 2
      now = Time.now
      Time.local(now.year, now.month, now.day, values[0], values[1], 0, 0)
    when 3 then Date.new(*values)
    else DateTime.new(*values)
    end

  end

  hash

end
serialize_attribute(attribute, raw_value) click to toggle source
# File lib/aws/record/abstract_base.rb, line 429
def serialize_attribute attribute, raw_value
  type_casted_value = type_cast(attribute, raw_value)
  case type_casted_value
  when nil then nil
  when Set then type_casted_value.map{|v| attribute.serialize(v) }
  else attribute.serialize(type_casted_value)
  end
end
serialize_attributes() click to toggle source
# File lib/aws/record/abstract_base.rb, line 411
def serialize_attributes

  hash = {}
  self.class.attributes.each_pair do |attribute_name,attribute|
    value = serialize_attribute(attribute, @_data[attribute_name])
    unless [nil, []].include?(value)
      hash[attribute_name] = value
    end
  end

  # simple db does not support persisting items without attribute values
  raise EmptyRecordError.new(self) if hash.empty?

  hash

end
type_cast(attribute, raw) click to toggle source
# File lib/aws/record/abstract_base.rb, line 398
def type_cast attribute, raw
  if attribute.set?
    values = Record.as_array(raw).inject([]) do |values,value|
      values << attribute.type_cast(value)
      values
    end
    Set.new(values.compact)
  else
    attribute.type_cast(raw)
  end
end
update() click to toggle source
# File lib/aws/record/abstract_base.rb, line 275
def update
  return unless changed?
  touch_timestamps('updated_at')
  increment_optimistic_lock_value
  update_storage
end