2.7. Behavior
Active Record lets you manipulate and find table
data directly through Active Record classes and instances. If you
want to work with data from a table, use the class. If you want to
work with a table row, use an instance. ActiveRecord::Base
class supplies many of the methods, and missing_method
provides most of the rest. You can find the documentation for the
latest stable Active Record version online at the following
address: http://api.rubyonrails.com.
2.7.1.
Finders
You can use other finders as well.
find_by_sql lets you type SQL directly into a finder;
find_all returns all records. In addition, Active Record
adds a custom finder called find_by_<column_name> to
each model class for each column in that model's table.
Let's use some of the methods on Photo.
We'll use a finder and the destroy method to delete an
object from the database:
Photo.find_by_filename("balboa_park.jpg").destroy
The methods delete and destroy
are slightly different. delete aborts on minor errors, but
destroy does not abort unless there's a critical database
error. You can also update objects. Let's update the Photo
object for cat.jpg:
>> cat=Photo.find_by_filename "cat.jpg"
...
>> cat.filename="Cat.jpg"
...
>> cat.update
...
>> puts cat.reload.filename
Cat.jpg
...
In this case, we found the cat.jpg record. We next updated the
filename attribute and called update to write the
changes to the database.
2.7.2.
Validation
So far, you've used Active Record to do database
operations on an object. You can also use Active Record for simple
validation. For example, you can verify that the
filename property exists with one line of code. Change the
Photo class in app/models/photo.rb to look like this:
class Photo < ActiveRecord::Base
validates_presence_of :filename
end
Let's see how the validation works. Go back to
the console (you'll need to restart it to reload your changes), and
try to save a blank photo:
>> photo=Photo.new
=> #<Photo:0x3501b70 @attributes={"filename"=>""}, @new_record=true>
>> photo.save
=> false
The save failed. Let's find out why:
>> photo.errors.each {|attribute, error| puts attribute + ": " +error}
filename: can't be blank
=> {"filename"=>["can't be blank"]}
You can do several different kinds of
validation, or you can create your own. You could validate an email
message like this:
validates_format_of :email,
:with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
Or you could validate the length of a field like
this:
validates_length_of :name, :within => 6..100
Later, you'll see that the Rails view
integration uses this information to present meaningful error
messages; look for those details in
"rubyrails-chp-5.html#rubyrails-chp-5">Chapter 5. You've seen
the basics of working with Active Record classes. You use a model
object or its class to directly manipulate rows in the database
table. Active Record goes beyond most traditional wrapping
frameworks because it helps you manage relationships between
tables. In the next few s, let's look into how Active Record
manages simple relationships.
2.7.3.
Transactions
Photo Share doesn't require
transactions, but for many applications, transactional
behavior is critical. If you have some code that must be executed
as a single unit, you can use Active Record transactions. The most
common example is a transfer between two accounts. A transfer is
fundamentally a debit and a credit. The Ruby code for a transfer
between from and to Active Record
Account models might look like this:
def transfer(from, to, amount)
from.debit(amount)
to.credit(amount)
end
You wouldn't want this method to fail after the
debitif it did, the holder of the from account would be
shorted by amount. So you use a transaction. This is the
way it works:
def transfer(from, to, amount)
Account.transaction do
from.debit(amount)
to.credit(amount)
end
end
transaction is a method on all Active
Record classes. With this approach, you can maintain the integrity
of your transactions.
|