Class AWS::Record::Base
In: lib/aws/record/base.rb
lib/aws/record/errors.rb
Parent: Object

An ActiveRecord-like interface built ontop of AWS.

  class Book < AWS::Record::Base

    string_attr :title
    string_attr :author
    integer :number_of_pages

    timestamps # adds a :created_at and :updated_at pair of timestamps

  end

  b = Book.new(:title => 'My Book', :author => 'Me', :pages => 1)
  b.save

Attribute Macros

When extending AWS::Record::Base you should first consider what attributes your class should have. Unlike ActiveRecord, AWS::Record models are not backed by a database table/schema. You must choose what attributes (and what types) you need.

  • string_attr
  • boolean_attr
  • integer_attr
  • float_attr
  • datetime_attr

For more information about the various attribute macros available, and what options they accept, see {AttributeMacros}.

Usage

Normally you just call these methods inside your model class definition:

  class Book < AWS::Record::Base
    string_attr :title
    boolean_attr :has_been_read
    integer_attr :number_of_pages
    float_attr :weight_in_pounds
    datetime_attr :published_at
  end

For each attribute macro a pair of setter/getter methods are added # to your class (and a few other useful methods).

  b = Book.new
  b.title = "My Book"
  b.has_been_read = true
  b.number_of_pages = 1000
  b.weight_in_pounds = 1.1
  b.published_at = Time.now
  b.save

  b.id #=> "0aa894ca-8223-4d34-831e-e5134b2bb71c"
  b.attributes
  #=> { 'title' => 'My Book', 'has_been_read' => true, ... }

Default Values

All attribute macros accept the +:default_value+ option. This sets a value that is populated onto all new instnaces of the class.

  class Book < AWS::Record::Base
    string_attr :author, :deafult_value => 'Me'
  end

  Book.new.author #=> 'Me'

Multi-Valued (Set) Attributes

AWS::Record permits storing multiple values with a single attribute.

  class Book < AWS::Record::Base
    string_attr :tags, :set => true
  end

  b = Book.new
  b.tags #=> #<Set: {}>

  b.tags = ['fiction', 'fantasy']
  b.tags #=> #<Set: {'fiction', 'fantasy'}>

These multi-valued attributes are treated as sets, not arrays. This means:

  • values are unordered
  • duplicate values are automatically omitted

Please consider these limitations when you choose to use the +:set+ option with the attribute macros.

Validations

It‘s important to validate models before there are persisted to keep your data clean. AWS::Record supports most of the ActiveRecord style validators.

  class Book < AWS::Record::Base
    string_attr :title
    validates_presence_of :title
  end

  b = Book.new
  b.valid? #=> false
  b.errors.full_messages #=> ['Title may not be blank']

Validations are checked before saving a record. If any of the validators adds an error, the the save will fail.

For more information about the available validation methods see {Validations}.

Finder Methods

You can find records by their ID. Each record gets a UUID when it is saved for the first time. You can use this ID to fetch the record at a latter time:

  b = Book["0aa894ca-8223-4d34-831e-e5134b2bb71c"]

  b = Book.find("0aa894ca-8223-4d34-831e-e5134b2bb71c")

If you try to find a record by ID that has no data an error will be raised.

All

You can enumerate all of your records using all.

  Book.all.each do |book|
    puts book.id
  end

  Book.find(:all) do |book|
    puts book.id
  end

Be careful when enumerating all. Depending on the number of records and number of attributes each record has, this can take a while, causing quite a few requests.

First

If you only want a single record, you should use first.

  b = Book.first

Modifiers

Frequently you do not want ALL records or the very first record. You can pass options to find, all and first.

  my_books = Book.find(:all, :where => 'owner = "Me"')

  book = Book.first(:where => { :has_been_read => false })

You can pass as find options:

  • +:where+ - Conditions that must be met to be returned
  • +:order+ - The order to sort matched records by
  • +:limit+ - The maximum number of records to return

Scopes

More useful than writing query fragments all over the place is to name your most common conditions for reuse.

  class Book < AWS::Record::Base

    scope :mine, where(:owner => 'Me')

    scope :unread, where(:has_been_read => false)

    scope :by_popularity, order(:score, :desc)

    scope :top_10, by_popularity.limit(10)

  end

  # The following expression returns 10 books that belong
  # to me, that are unread sorted by popularity.
  next_good_reads = Book.mine.unread.top_10

There are 3 standard scope methods:

  • where
  • order
  • limit

Conditions (where)

Where accepts aruments in a number of forms:

  1. As an sql-like fragment. If you need to escape values this form is not suggested.
      Book.where('title = "My Book"')
    
  2. An sql-like fragment, with placeholders. This escapes quoted arguments properly to avoid injection.
      Book.where('title = ?', 'My Book')
    
  3. A hash of key-value pairs. This is the simplest form, but also the least flexible. You can not use this form if you need more complex expressions that use or.
      Book.where(:title => 'My Book')
    

Order

This orders the records as returned by AWS. Default ordering is ascending. Pass the value :desc as a second argument to sort in reverse ordering.

  Book.order(:title)        # alphabetical ordering
  Book.order(:title, :desc) # reverse alphabetical ordering

You may only order by a single attribute. If you call order twice in the chain, the last call gets presedence:

  Book.order(:title).order(:price)

In this example the books will be ordered by :price and the order(:title) is lost.

Limit

Just call limit with an integer argument. This sets the maximum number of records to retrieve:

  Book.limit(2)

Delayed Execution

It should be noted that all finds are lazy (except first). This means the value returned is not an array of records, rather a handle to a {Scope} object that will return records when you enumerate over them.

This allows you to build an expression without making unecessary requests. In the following example no request is made until the call to each_with_index.

  all_books = Books.all
  ten_books = all_books.limit(10)

  ten_books.each_with_index do |book,n|
    puts "#{n + 1} : #{book.title}"
  end

Methods

Included Modules

Naming Conversion DirtyTracking

Public Class methods

@return [Hash<String,Attribute>] Returns a hash of all of the

  configured attributes for this class.

Creates the SimpleDB domain that is configured for this class.

@return [String] Returns the full prefixed domain name for this class.

Constructs a new record for this class/domain.

@param [Hash] attributes A set of attribute values to seed this record

  with.  The attributes are bulk assigned.

@return [Base] Returns a new record that has not been persisted yet.

@return [AWS::SimpleDB::Domain] Returns a reference to the domain

  this class will save data to.

@private

Allows you to override the default domain name for this record. The defualt domain name is the class name. @param [String] The domain name that should be used for this class.

Public Instance methods

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

  attribute values (of mixed types) as hash values.

Deletes the record. @return (see delete_item)

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

The id for each record is auto-generated. The default strategy generates uuid strings. @return [String] Returns the id string (uuid) for this record. Retuns

  nil if this is a new record that has not been persisted yet.

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

  to SimpleDB.

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.

Creates new records, updates existing records. @return [Boolean] Returns true if the record saved without errors,

  false otherwise.

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.

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)

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]

@return [Boolean] Returns true if this record has no validation errors.

Protected Instance methods

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::Base

    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.

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

  class Book < AWS::Record::Base

    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.

[Validate]