Class: AWS::Record::Base
- Inherits:
-
Object
- Object
- AWS::Record::Base
- Extended by:
- AttributeMacros, FinderMethods, OptimisticLocking, Scopes, Validations
- Includes:
- DirtyTracking
- Defined in:
- lib/aws/record/base.rb,
lib/aws/record/errors.rb
Overview
An ActiveRecord-like interface built ontop of AWS.
class Book < AWS::Record::Base
string_attr :title
string_attr :author
integer :number_of_pages
# 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. #=> '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. #=> #<Set: {}>
b. = ['fiction', 'fantasy']
b. #=> #<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. #=> ['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:
-
As an sql-like fragment. If you need to escape values this form is not suggested.
Book.where('title = "My Book"')
-
An sql-like fragment, with placeholders. This escapes quoted arguments properly to avoid injection.
Book.where('title = ?', 'My Book')
-
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
Class Method Summary collapse
-
.attributes ⇒ Hash<String,Attribute>
Returns a hash of all of the configured attributes for this class.
-
.create_domain ⇒ Object
Creates the SimpleDB domain that is configured for this class.
-
.domain_name ⇒ String
Returns the full prefixed domain name for this class.
-
.set_domain_name(name) ⇒ Object
Allows you to override the default domain name for this record.
Instance Method Summary collapse
-
#attributes ⇒ Hash
A hash with attribute names as hash keys (strings) and attribute values (of mixed types) as hash values.
-
#delete ⇒ Object
Deletes the record.
-
#deleted? ⇒ Boolean
Returns true if this instance object has been deleted.
- #errors ⇒ Object
-
#id ⇒ String
The id for each record is auto-generated.
-
#initialize(attributes = {}) ⇒ Base
constructor
Constructs a new record for this class/domain.
-
#new_record? ⇒ Boolean
Returns true if this record has not been persisted to SimpleDB.
-
#persisted? ⇒ Boolean
Persistence indicates if the record has been saved previously or not.
-
#save ⇒ Boolean
Creates new records, updates existing records.
-
#save! ⇒ true
Creates new records, updates exsting records.
-
#update_attributes(attribute_hash) ⇒ Boolean
Bulk assigns the attributes and then saves the record.
-
#update_attributes!(attribute_hash) ⇒ true
Bulk assigns the attributes and then saves the record.
-
#valid? ⇒ Boolean
Returns true if this record has no validation errors.
Methods included from Validations
validates_acceptance_of, validates_confirmation_of, validates_count_of, validates_each, validates_exclusion_of, validates_format_of, validates_inclusion_of, validates_length_of, validates_numericality_of, validates_presence_of
Methods included from AttributeMacros
boolean_attr, datetime_attr, float_attr, integer_attr, sortable_float_attr, sortable_integer_attr, string_attr, timestamps
Methods included from FinderMethods
all, count, find, first, limit, order, where
Methods included from OptimisticLocking
Methods included from Scopes
Methods included from DirtyTracking
Constructor Details
#initialize(attributes = {}) ⇒ Base
Constructs a new record for this class/domain.
304 305 306 307 308 |
# File 'lib/aws/record/base.rb', line 304 def initialize attributes = {} @_data = {} assign_default_values bulk_assign(attributes) end |
Class Method Details
.attributes ⇒ Hash<String,Attribute>
Returns a hash of all of the configured attributes for this class.
422 423 424 |
# File 'lib/aws/record/base.rb', line 422 def attributes @attributes ||= {} end |
.create_domain ⇒ Object
Creates the SimpleDB domain that is configured for this class.
440 441 442 |
# File 'lib/aws/record/base.rb', line 440 def create_domain AWS::SimpleDB.new.domains.create(domain_name) end |
.domain_name ⇒ String
Returns the full prefixed domain name for this class.
434 435 436 437 |
# File 'lib/aws/record/base.rb', line 434 def domain_name @_domain_name ||= self.to_s "#{Record.domain_prefix}#{@_domain_name}" end |
.set_domain_name(name) ⇒ Object
Allows you to override the default domain name for this record.
The defualt domain name is the class name.
429 430 431 |
# File 'lib/aws/record/base.rb', line 429 def set_domain_name name @_domain_name = name end |
Instance Method Details
#attributes ⇒ Hash
Returns A hash with attribute names as hash keys (strings) and attribute values (of mixed types) as hash values.
320 321 322 323 324 325 326 327 |
# File 'lib/aws/record/base.rb', line 320 def attributes attributes = IndifferentHash.new attributes['id'] = id if persisted? self.class.attributes.keys.inject(attributes) do |hash,attr_name| hash[attr_name] = __send__(attr_name) hash end end |
#delete ⇒ Object
Deletes the record.
401 402 403 404 405 406 407 408 409 410 411 |
# File 'lib/aws/record/base.rb', line 401 def delete if persisted? if deleted? raise 'unable to delete, this object has already been deleted' else delete_item end else raise 'unable to delete, this object has not been saved yet' end end |
#deleted? ⇒ Boolean
Returns true if this instance object has been deleted.
414 415 416 |
# File 'lib/aws/record/base.rb', line 414 def deleted? persisted? ? !!@_deleted : false end |
#errors ⇒ Object
21 22 23 |
# File 'lib/aws/record/errors.rb', line 21 def errors @errors ||= Errors.new end |
#id ⇒ String
The id for each record is auto-generated. The default strategy generates uuid strings.
314 315 316 |
# File 'lib/aws/record/base.rb', line 314 def id @_id end |
#new_record? ⇒ Boolean
Returns true if this record has not been persisted to SimpleDB.
344 345 346 |
# File 'lib/aws/record/base.rb', line 344 def new_record? !persisted? end |
#persisted? ⇒ Boolean
Persistence indicates if the record has been saved previously or not.
338 339 340 |
# File 'lib/aws/record/base.rb', line 338 def persisted? !!@_persisted end |
#save ⇒ Boolean
Creates new records, updates existing records.
357 358 359 360 361 362 363 364 365 |
# File 'lib/aws/record/base.rb', line 357 def save if valid? persisted? ? update : create clear_changes! true else false end end |
#save! ⇒ true
Creates new records, updates exsting records. If there is a validation error then an exception is raised.
372 373 374 375 |
# File 'lib/aws/record/base.rb', line 372 def save! raise InvalidRecordError.new(self) unless save true end |
#update_attributes(attribute_hash) ⇒ Boolean
Bulk assigns the attributes and then saves the record.
381 382 383 384 |
# File 'lib/aws/record/base.rb', line 381 def update_attributes attribute_hash bulk_assign(attribute_hash) save end |
#update_attributes!(attribute_hash) ⇒ true
Bulk assigns the attributes and then saves the record. Raises an exception (AWS::Record::InvalidRecordError) if the record is not valid.
391 392 393 394 395 396 397 |
# File 'lib/aws/record/base.rb', line 391 def update_attributes! attribute_hash if update_attributes(attribute_hash) true else raise InvalidRecordError.new(self) end end |
#valid? ⇒ Boolean
Returns true if this record has no validation errors.
349 350 351 352 |
# File 'lib/aws/record/base.rb', line 349 def valid? validate errors.empty? end |