ONLamp.com
oreilly.comSafari Books Online.Conferences.

advertisement


What Is Ruby on Rails
Pages: 1, 2, 3, 4, 5, 6, 7

Automated mapping

Active Record automatically maps tables to classes, rows to objects (instances of the model classes), and columns to object attributes. For example:



class Product < ActiveRecord::Base
end

automatically maps to the table named products, such as:

CREATE TABLE products (
  id int(11) NOT NULL auto_increment,
  name varchar(255),
  PRIMARY KEY (id)
);

which also automatically creates a name attribute that you can use like this:

my_product = Product.find(:first)
STDOUT.print my_product.name
my_product.name = "New Product Name"

Active Record uses English pluralization rules to map classes to tables. The model class name is singular and capitalized, while the table name is plural and lowercased. Examples include:

  • An Invoice model class maps to an invoices table.
  • A Person model class maps to a people table.
  • A Country model class maps to a countries table.
  • A SecurityLevel model class maps to a security_levels table.

This singular/plural convention results in code that reads fairly naturally. Notice how this mapping is intelligent in its use of English pluralization rules. Also note that the class names use CamelCase (a Ruby convention), while the table names are all lowercase with underscores between words.

In cases where this does not work (such as interfacing with a legacy database with which you have no control over the names), you can also explicitly tell Active Record what name it should use.

The ActiveRecord::Base documentation explains more about Active Record's automatic mapping.

Associations

No table stands alone. Well, not usually, anyway. Most database applications use multiple tables with specific relationships between those tables. You can tell Active Record about these relationships in your model classes, and Active Record will generate a slew of navigation methods that make it easy for your code to access related data. The following models:

class Firm < ActiveRecord::Base
  has_many   :clients
  has_one    :account
  belongs_to :conglomorate
end

allow you to write code such as this:

my_firm = Firm.find(:last)
STDOUT.print my_firm.account.name
STDOUT.print my_firm.conglomerate.employee_count
for c in my_firm.clients
  STDOUT.print "Client: " + c.name + "\n"
end

This code will work correctly when the database has a clients and accounts table, of which each has a name column, and a conglomerates table that has an employee_count column.

The ActiveRecord::Associations documentation explains more about associations.

Validation

Because you don't want to store just any old thing in your database, you probably want to validate your data before you store it. Active Record contains a suite of macrolike validators that you can add to your model.

class Account < ActiveRecord::Base
  validates_presence_of     :subdomain, :name, :email_address, :password
  validates_uniqueness_of   :subdomain
  validates_acceptance_of   :terms_of_service, :on => :create
  validates_confirmation_of :password, :email_address, :on => :create
end

If the built-in validation macros can't do what you need, you can always write your own validation methods.

class Person < ActiveRecord::Base
  protected
    def validate
      errors.add_on_empty %w( first_name last_name )
      errors.add("phone_number", "has invalid format") unless phone_number =~ /[0-9]*/
    end

    def validate_on_create # only runs the first time a new object is saved
      unless valid_discount?(membership_discount)
        errors.add("membership_discount", "has expired")
      end
    end

    def validate_on_update
      errors.add_to_base("No changes have occurred") if unchanged_attributes?
    end
end

person = Person.new("first_name" => "David", "phone_number" => "what?")
person.save                         # => false (and doesn't do the save)
person.errors.empty?                # => false
person.count                        # => 2
person.errors.on "last_name"        # => "can't be empty"
person.errors.on "phone_number"     # => "has invalid format"
person.each_full { |msg| puts msg } # => "Last name can't be empty\n" +
                                            "Phone number has invalid format"
person.attributes = { "last_name" => "Heinemeier", "phone_number" => "555-555" }
person.save # => true (and person is now saved in the database)

If the validate method exists, Rails will call it just before writing any object to the database. If validation fails, it does not write the object to the database. validate_on_create and validate_on_update are similar, except that the first is called only before Rails creates a new record in the database, while the second is called only when Rails is about to update an existing record.

You can also validate a particular attribute only when some condition is true.

# Conditional validations such as the following are possible:
  validates_numericality_of :income,   :if => :employed?
  validates_confirmation_of :password, :if => :new_password?

# Using blocks:
  validates_presence_of :username, :if => Proc.new { |user| user.signup_step > 1 }

The ActiveRecord::Validations documentation explains more about validation.

Pages: 1, 2, 3, 4, 5, 6, 7

Next Pagearrow





Sponsored by: