Introduction to Active Record at MySQL Conference 2007

72
Introduction to Active Record Evan ‘Rabble’ Henshaw-Plath [email protected] - Yahoo! Brickhouse anarchogeek.com - testingrails.com

description

An introduction to the ruby on rails Active Record library presented at the MySQL Users Conference in Santa Clara 2007.

Transcript of Introduction to Active Record at MySQL Conference 2007

Page 1: Introduction to Active Record at MySQL Conference 2007

Introduction to Active Record

Evan ‘Rabble’ Henshaw-Plath [email protected] - Yahoo! Brickhouse

anarchogeek.com - testingrails.com

Page 2: Introduction to Active Record at MySQL Conference 2007

Active Record is a Design Pattern

An object that wraps a row in a database table or view, encapsulates the database access, and

adds domain logic on that data.

Page 3: Introduction to Active Record at MySQL Conference 2007

Active Recordthe Pattern

Active Record uses the most obvious approach,putting data access logic in the domain object.

- Martin Fowler

Person last_name first_name dependents_count

insert update

get_exemption is_flagged_for_audit? get_taxable_earnings?

Page 4: Introduction to Active Record at MySQL Conference 2007

One Class Per Table

CREATE TABLE `users` ( `id` int(11) NOT NULL auto_increment, `login` varchar(255), `email` varchar(255), `crypted_password` varchar(40), `salt` varchar(40), `created_at` datetime default NULL, `updated_at` datetime default NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;

class User < ActiveRecord::Base end

The DatabaseThe Model Code

Page 5: Introduction to Active Record at MySQL Conference 2007

One Object Per Row

Page 6: Introduction to Active Record at MySQL Conference 2007

There Are Other Ways To Do it

• Table Data Gateway

• Row Data Gateway

• Data Mapper

• The Anti-Patterns

Active Record is just one ‘Data Source Architectural Pattern’

Page 7: Introduction to Active Record at MySQL Conference 2007

Standard Active Record

• Direct mapping to the DB

• Class to table

• Object to row

• Simple, no relationship between objects

• Just a finder method with getters and setters

Page 8: Introduction to Active Record at MySQL Conference 2007

ActiveRecordthe ruby library

Active Record is a library builtfor Ruby on Rails.

Makes CRUD EasyCreateReadUpdateDelete

Page 9: Introduction to Active Record at MySQL Conference 2007

ActiveRecordthe ruby library

I have never seen an Active Record implementation as complete

or as useful as rails. - Martin Fowler

Page 10: Introduction to Active Record at MySQL Conference 2007

Rails’ ActiveRecord• DRY Conventions & Assumptions

• Validations

• Before and after filters

• Database Agnostic (mostly)

• Migrations

• Model relationships

• has_many, belongs_to, etc...

Page 11: Introduction to Active Record at MySQL Conference 2007

What ActiveRecord Likes• mapping class names to

table names

• pluralized table names

• integer primary keys

• classname_id foreign keys

• simple schemas

• single table inheritance

Page 12: Introduction to Active Record at MySQL Conference 2007

Active RecordDoesn’t Like • views

• stored procedures

• foreign key constraints

• cascading commits

• split or clustered db’s

• enums

Page 13: Introduction to Active Record at MySQL Conference 2007

The Basics

class User < ActiveRecord::Base end

./app/models/user.rb Loading a user

>> user_obj = User.find(2)=> #<User:0x352e8bc @attributes= {"salt"=>"d9ef...", "updated_at"=>"2007-04-19 10:49:15", "crypted_password"=>"9c1...", "id"=>"2", "remember_token"=>"a8d...", "login"=>"rabble", "created_at"=>"2007-04-19 10:49:15", "email"=>"[email protected]"}>

User Load (0.003175) SELECT * FROM users WHERE (users.id = 2) LIMIT 1

The SQL Log

Page 14: Introduction to Active Record at MySQL Conference 2007

The Find Method

Find is the primary method of Active Record

Examples: User.find(23) User.find(:first) User.find(:all, :offset => 10, :limit => 10) User.find(:all, :include => [:account, :friends]) User.find(:all, :conditions => [“category in (?), categories, :limit => 50) User.find(:first).articles

Page 15: Introduction to Active Record at MySQL Conference 2007

The Four Ways of Find

Find by id: This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).

Find first: This will return the first record matched by the options used.

Find all: This will return all the records matched by the options used.

Indirectly: The find method is used for AR lookups via associations.

Page 16: Introduction to Active Record at MySQL Conference 2007

Understanding Find

Model#find(:all, { parameters hash }

What Find Does: * generates sql * executes sql * returns an enumerable (array like object) * creates an AR model object for each row

Page 17: Introduction to Active Record at MySQL Conference 2007

Find with :conditions

:conditions - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ].

Student.find(:all, :conditions => [‘first_name = ? and status = ?’ ‘rabble’, 1])

New Style (Edge Rails Only)Student.find(:all, :conditions => {:first_name => “rabble”, :status => 1})

SQL Executed:SELECT * FROM students WHERE (first_name = 'rabble' and status = 1);

Page 18: Introduction to Active Record at MySQL Conference 2007

Order By

:order - An SQL fragment like "created_at DESC, name".

Student.find(:all, :order => ‘updated_at DESC’)

SQL Executed:SELECT * FROM users ORDER BY created_at;

Page 19: Introduction to Active Record at MySQL Conference 2007

Group By

:group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.

Student.find(:all, :group => ‘graduating_class’)

SQL Executed:SELECT * FROM users GROUP BY graduating_class;

Page 20: Introduction to Active Record at MySQL Conference 2007

Limit & Offset:limit - An integer determining the limit on the number of rows that should be returned.

:offset- An integer determining the offset from where the rows should be fetched. So at 5, it would skip the first 4 rows.

Student.find(:all, :limit => 10, :offset => 0)

SQL Executed:SELECT * FROM users LIMIT 0, 10;

Page 21: Introduction to Active Record at MySQL Conference 2007

Joins

:joins - An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". (Rarely needed).

Student.find(:all, :join => "LEFT JOIN comments ON comments.post_id = id")

SQL Executed:SELECT users.* FROM users, comments LEFT JOIN comments ON comments.post_id = users.id;

Returns read only objects unless you say :readonly => false

Page 22: Introduction to Active Record at MySQL Conference 2007

Alternative Finds

find_by_sql

find_by_attribute_and_attribute2

find_or_create

Depreciated Find’sfind_firstfind_allfind_on_conditions

Page 23: Introduction to Active Record at MySQL Conference 2007

class Project < ActiveRecord::Base belongs_to :portfolio has_one :project_manager has_many :milestones has_and_belongs_to_many :categoriesend

The Four Primary Associations

belongs_tohas_onehas_manyhas_and_belongs_to_many

Associations

Page 24: Introduction to Active Record at MySQL Conference 2007

One to One has_one & belongs_to

Many to One has_many & belongs_to

Many to Many has_and_belongs_to_many has_many :through

Associations

Page 25: Introduction to Active Record at MySQL Conference 2007

One to One

Use has_one in the base, and belongs_to in the associated model.

class Employee < ActiveRecord::Base has_one :office end

class Office < ActiveRecord::Base belongs_to :employee # foreign key - employee_id end

Page 26: Introduction to Active Record at MySQL Conference 2007

One To One Example>> joe_employee = Employee.find_by_first_name('joe')SELECT * FROM employees WHERE (employees.`first_name` = 'joe') LIMIT 1=> #<Employee:0x36beb14 @attributes={"id"=>"1", "first_name"=>"joe", "last_name"=>"schmo", "created_at"=>"2007-04-21 09:08:59"}>

>> joes_office = joe_employee.officeSELECT * FROM offices WHERE (offices.employee_id = 1) LIMIT 1=> #<Office:0x36bc06c @attributes={"employee_id"=>"1", "id"=>"1", "created_at"=>"2007-04-21 09:11:44", "location"=>"A4302"}>

>> joes_office.employeeSELECT * FROM employees WHERE (employees.`id` = 1)=> #<Employee:0x36b6ef0 @attributes={"id"=>"1", "first_name"=>"joe", "last_name"=>"schmo", "created_at"=>"2007-04-21 09:08:59"}>

Page 27: Introduction to Active Record at MySQL Conference 2007

belongs_toOne to One Relationship. Use belong to when the foreign key is in THIS table.

• Post#author (similar to Author.find(author_id) )

• Post#author=(author) (similar to post.author_id = author.id)

• Post#author? (similar to post.author == some_author)

• Post#author.nil?

• Post#build_author (similar to post.author = Author.new)

• Post#create_author (similar to post.author = Author; post.author.save;

Page 28: Introduction to Active Record at MySQL Conference 2007

Defining belongs_toclass Employee < ActiveRecord::Base belongs_to :firm, :foreign_key => "client_of"

belongs_to :author, :class_name => "Person", :foreign_key => "author_id"

belongs_to :valid_coupon, :class_name => "Coupon",

:foreign_key => "coupon_id", :conditions => 'discounts > #{payments_count}'

belongs_to :attachable, :polymorphic => trueend

Page 29: Introduction to Active Record at MySQL Conference 2007

has_one

• Account#beneficiary (similar to Beneficiary.find(:first, :conditions => "account_id = #{id}"))

• Account#beneficiary=(beneficiary) (similar to beneficiary.account_id = account.id; beneficiary.save)

• Account#beneficiary.nil?

• Account#build_beneficiary (similar to Beneficiary.new("account_id" => id))

• Account#create_beneficiary (similar to b = Beneficiary.new("account_id" => id); b.save; b)

One to One Relationship. Use has_one when the foreign key is in the OTHER table.

Page 30: Introduction to Active Record at MySQL Conference 2007

Defining has_oneclass Employee < ActiveRecord::Base

# destroys the associated credit card has_one :credit_card, :dependent => :destroy # updates the associated records foreign key value to null rather than destroying it has_one :credit_card, :dependent => :nullify has_one :last_comment, :class_name => "Comment", :order => "posted_on" has_one :project_manager, :class_name => "Person", :conditions => "role = 'project_manager'"

has_one :attachment, :as => :attachable

end

Page 31: Introduction to Active Record at MySQL Conference 2007

One to ManyOne-to-manyUse has_many in the base, and belongs_to in the associated model.

class Manager < ActiveRecord::Base has_many :employeesend

class Employee < ActiveRecord::Base belongs_to :manager # foreign key - manager_idend

Page 32: Introduction to Active Record at MySQL Conference 2007

>> benevolent_dictator = Manager.find(:first, :conditions => ['name = "DHH"']) SELECT * FROM managers WHERE (name = "DHH") LIMIT 1=> #<Manager:0x369b7b8 @attributes={"name"=>"DHH", "id"=>"1", "created_at"=>"2007-04-21 09:59:24"}>

>> minions = benevolent_dictator.employees SELECT * FROM employees WHERE (employees.manager_id = 1)=> [#<Employee:0x36926a4 @attributes={"manager_id"=>"1", "id"=>"1", "first_name"=>"joe", "last_name"=>"schmo", "created_at"=>"2007-04-21 09:08:59"}>, #<Employee:0x36925f0 @attributes={"manager_id"=>"1", "id"=>"2", "first_name"=>"funky", "last_name"=>"monkey", "created_at"=>"2007-04-21 09:58:20"}>]

One to Many

Page 33: Introduction to Active Record at MySQL Conference 2007

has_many

• Firm#clients (similar to Clients.find :all, :conditions => "firm_id = #{id}")

• Firm#clients<<

• Firm#clients.delete

• Firm#client_ids

• Firm#client_ids=

• Firm#clients=

Augmenting the Model

Page 34: Introduction to Active Record at MySQL Conference 2007

has_many

• Firm#client.clear

• Firm#clients.empty? (similar to firm.clients.size == 0)

• Firm#clients.size (similar to Client.count "firm_id = #{id}")

• Firm#clients.find (similar to Client.find(id, :conditions => "firm_id = #{id}"))

• Firm#clients.build (similar to Client.new("firm_id" => id))

• Firm#clients.create (similar to c = Client.new("firm_id" => id); c.save; c)

Page 35: Introduction to Active Record at MySQL Conference 2007

has_many examples

class Employee < ActiveRecord::Base has_many :comments, :order => "posted_on" has_many :comments, :include => :author has_many :people, :class_name => "Person", :conditions => "deleted = 0", :order => "name" has_many :tracks, :order => "position", :dependent => :destroy has_many :comments, :dependent => :nullify has_many :tags, :as => :taggable has_many :subscribers, :through => :subscriptions, :source => :user has_many :subscribers, :class_name => "Person", :finder_sql => 'SELECT DISTINCT people.* ' + 'FROM people p, post_subscriptions ps ' + 'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' + 'ORDER BY p.first_name'end

Page 36: Introduction to Active Record at MySQL Conference 2007

Many to Many

Simple Joiner Tablehas_and_belongs_to_many

Joiner Modelhas_many :through

Page 37: Introduction to Active Record at MySQL Conference 2007

has_and_belongs_to_many

The Simple Joiner Table Way

Page 38: Introduction to Active Record at MySQL Conference 2007

neglected by

rails-core

has_and_belongs_to_many

Page 39: Introduction to Active Record at MySQL Conference 2007

has_and_belongs_to_many

• Developer#projects

• Developer#projects<<

• Developer#projects.delete

• Developer#projects=

• Developer#projects_ids

• Developer#projects_ids=

• Developer#clear

Augmenting the Model

Page 40: Introduction to Active Record at MySQL Conference 2007

has_and_belongs_to_many

• Developer#projects.empty?

• Developer#projects.size

• Developer#projects.find(id) # Also find(:first / :all)

• Developer#projects.build #(similar to Project.new("project_id" => id))

• Developer#projects.create (similar to c = Project.new("project_id" => id); c.save; c)

Page 41: Introduction to Active Record at MySQL Conference 2007

habtm example create_table :developers do |t| t.column :name, :string t.column :created_at, :datetime end

create_table :projects do |t| t.column :name, :string t.column :created_at, :datetime end

create_table(:developers_projects, :id => false) do |t| t.column :developer_id, :integer t.column :project_id, :integer end

Page 42: Introduction to Active Record at MySQL Conference 2007

habtm example>> d = Developer.find(1) SELECT * FROM developers WHERE (developers.`id` = 1)=> #<Developer:0x32bc7dc @attributes={"name"=>"rabble", "id"=>"1", "created_at"=>nil}>

>> d.projects SELECT * FROM projects INNER JOIN developers_projects ON projects.id = developers_projects.project_id WHERE (developers_projects.developer_id = 1 )=> [#<Project:0x3257cc4 @attributes= {"name"=>"ragi", "project_id"=>"1", "id"=>"1", "developer_id"=>"1", "created_at"=>nil}>, #<Project:0x3257c10 @attributes= {"name"=>"acts_as_autenticated", "project_id"=>"3", "id"=>"3", "developer_id"=>"1", "created_at"=>nil}>]

Page 43: Introduction to Active Record at MySQL Conference 2007

has_many :through

DHH’s One True Way

of Many to Many

Page 44: Introduction to Active Record at MySQL Conference 2007

has_many :through

Full Joiner Model

Page 45: Introduction to Active Record at MySQL Conference 2007

has_many :through

class Appearance < ActiveRecord::Base belongs_to :dancer belongs_to :movieend

class Dancer < ActiveRecord::Base has_many :appearances, :dependent => true has_many :movies, :through => :appearancesend

class Movie < ActiveRecord::Base has_many :appearances, :dependent => true has_many :dancers, :through => :appearancesend

Page 46: Introduction to Active Record at MySQL Conference 2007

Validations

class User < ActiveRecord::Base validates_confirmation_of :login, :password validates_confirmation_of :email, :message => "should match confirmation" validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :createend

Page 47: Introduction to Active Record at MySQL Conference 2007

Validations

• Keeping Data Clean

• In object validation of fields, calculated validations

• Instead of key constraints

• The database is for storage, the model is for the business logic

• Kinds of validations, custom validations, etc...

Page 48: Introduction to Active Record at MySQL Conference 2007

But Wait?

• Aren’t format, presence, relationship validations supposed to be the database’s job?

• Traditionally, yes.

• ActiveRecord does constraints in the model, not the database

Page 49: Introduction to Active Record at MySQL Conference 2007

But Why?

• Validations & Constraints are Business Logic

• Business logic should be in the model

• It makes things easy

• End users can get useful error messages

• Makes the postback pattern work well

Page 50: Introduction to Active Record at MySQL Conference 2007

Data Integrity?

• It’s still possible to do constraints in the db

• But it’s not as necessary

• Validations are constraints which make sense in terms of functionality of the app

• The rails ways is to just use validations

• Most DBA’s insist on foreign_key constraints

Page 51: Introduction to Active Record at MySQL Conference 2007

What AR Returns?

• Arrays of Model Objects

• Preselects and instantiates objects

• Nifty methods: to_yaml, to_xml, to_json

Page 52: Introduction to Active Record at MySQL Conference 2007

Output Formats#<Employee:0x36926a4 @attributes= {"manager_id"=>"1", "id"=>"1", "first_name"=>"joe", "last_name"=>"schmo", "created_at"=>"2007-04-21 09:08:59"}>

ruby - inspect--- !ruby/object:Employee attributes: manager_id: "1" id: "1" first_name: joe last_name: schmo created_at: 2007-04-21 09:08:59

to_yaml

{attributes: {manager_id: "1", id: "1", first_name: "joe", last_name: "schmo", created_at: "2007-04-21 09:08:59"}}

to_json<?xml version="1.0" encoding="UTF-8"?><employee> <created-at type="datetime">2007-04-21T09:08:59-07:00</created-at> <first-name>joe</first-name> <id type="integer">1</id> <last-name>schmo</last-name> <manager-id type="integer">1</manager-id></employee>

to_xml

Page 53: Introduction to Active Record at MySQL Conference 2007

Before & After Callbacks

* (-) save * (-) valid? * (1) before_validation * (2) before_validation_on_create * (-) validate * (-) validate_on_create * (3) after_validation * (4) after_validation_on_create * (5) before_save * (6) before_create * (-) create * (7) after_create * (8) after_save

class Subscription < ActiveRecord::Base before_create :record_signup

private def record_signup self.signed_up_on = Date.today end end

class Firm < ActiveRecord::Base # Destroys the associated clients and #people when the firm is destroyed before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" } before_destroy { |record| Client.destroy_all "client_of = #{record.id}" } end

Page 54: Introduction to Active Record at MySQL Conference 2007

Optimizing AR

• Eager Loading

• Use Memecached

• Add index to your migrations

Page 55: Introduction to Active Record at MySQL Conference 2007

Security

Page 56: Introduction to Active Record at MySQL Conference 2007

Doing it Securely

class User < ActiveRecord::Base def self.authenticate_unsafely(user_name, password) find(:first, :conditions => "user_name = '#{user_name}' AND password = '#{password}'") end

def self.authenticate_safely(user_name, password) find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ]) end

# Edge Rails Only (Rails 2.0) def self.authenticate_safely_simply(user_name, password) find(:first, :conditions => { :user_name => user_name, :password => password }) end end

Page 57: Introduction to Active Record at MySQL Conference 2007

Examples Stolen From: http://www.therailsway.com/2007/3/26/association-proxies-are-your-friend

Use The ActiveRecord Relationships

Anti-Pattern #1: Manually specifying the IDs when you construct the queries;def show unless @todo_list = TodoList.find_by_id_and_user_id(params[:id], current_user.id) redirect_to '/'end

Anti-Pattern #2: Querying globally, then checking ownership after the fact;def show @todo_list = TodoList.find(params[:id]) redirect_to '/' unless @todo_list.user_id = current_user.idend

Anti-Pattern #3: Abusing with_scope for a this simple case either directly, or in an around_filter.def show with_scope(:find=>{:user_id=>current_user.id}) do @todo_list = TodoList.find(params[:id]) endend

Best Practice: The most effective way to do this is to call find on the todo_lists association.def show @todo_list = current_user.todo_lists.find(params[:id])end

Page 58: Introduction to Active Record at MySQL Conference 2007

Create Via Association Proxies

The Bad Waydef create @todo_list = TodoList.new(params[:todo_list]) @todo_list.user_id = current_user.id @todo_list.save! redirect_to todo_list_url(@todo_list)end

A Better Way: Use association proxies for creation.def create @todo_list = current_user.todo_lists.create! params[:todo_list] redirect_to todo_list_url(@todo_list)end

The Best Practice - Handle exceptions for the user.def create @todo_list = current_user.todo_lists.build params[:todo_list] if @todo_list.save redirect_to todo_list_url(@todo_list) else render :action=>'new' endend Examples Stolen From: http://www.therailsway.com/2007/3/26/association-proxies-are-your-friend

Page 59: Introduction to Active Record at MySQL Conference 2007

Special Fields * created_at * created_on * updated_at * updated_on * lock_version * type * id

* #{table_name}_count * position * parent_id * lft * rgt * quote * template

Page 60: Introduction to Active Record at MySQL Conference 2007

Table Inheritance

Class Table Inheritance: Represents an inheritance hierarchy of classes with one table for each class1.

Single Table Inheritance: Represents an inheritance hierarchy of classes as a single table that has columns for all the fields of the various classes2.

Concrete Table Inheritance: Represents an inheritance hierarchy of classes with one table per concrete class in the hierarchy

Page 61: Introduction to Active Record at MySQL Conference 2007

STI - Single Table Inheritance Represents an inheritance hierarchy of classes as a single

table that has columns for all the fields of the various classes.

Page 62: Introduction to Active Record at MySQL Conference 2007

STI - Single Table Inheritance

class Company < ActiveRecord::Base; end class Firm < Company; end class Client < Company; end class PriorityClient < Client; end

CREATE TABLE `companies` ( `id` int(11) default NULL, `name` varchar(255) default NULL, `type` varchar(32) default NULL)

Company.find(:first) SELECT * FROM companies LIMIT 1;

Firm.find(:first) SELECT * FROM companies WHERE type = ‘firm’ LIMIT 1;

Page 63: Introduction to Active Record at MySQL Conference 2007

Legacy Databases

How to do legacy databases with Active Record?

http://sl33p3r.free.fr/tutorials/rails/legacy/legacy_databases.html

Page 64: Introduction to Active Record at MySQL Conference 2007

class CustomerNote < ActiveRecord::Base

set_primary_key "client_comment_id" set_sequence_name "FooBarSequences"

def self.table_name() "client_comment" end def body read_attribute "client_comment_body" end

def body=(value) write_attribute "client_comment_body", value endend

Supporting Legacy DB’s

Thanks to: http://www.robbyonrails.com/articles/2005/07/25/the-legacy-of-databases-with-rails

Page 65: Introduction to Active Record at MySQL Conference 2007

Changing ActiveRecord

Thanks to: http://fora.pragprog.com/rails-recipes/write-your-own/post/84

Modify Active Record ActiveRecord::Base.table_name_prefix = "my_" ActiveRecord::Base.table_name_suffix = "_table" ActiveRecord::Base.pluralize_table_names = false

Fixing the Auto-Increment / Sequence Problem module ActiveRecord class Base class << self def reset_sequence_name "#{table_name}_sequence" end end end end

module ActiveRecord module ConnectionAdapters class MysqlAdapter def prefetch_primary_key?(table_name = nil) true end end end end

Page 66: Introduction to Active Record at MySQL Conference 2007

Changing ActiveRecord

Thanks to: http://fora.pragprog.com/rails-recipes/write-your-own/post/84

Telling ActiveRecord to fetch the primary key

module ActiveRecord module ConnectionAdapters class MysqlAdapter

def prefetch_primary_key?(table_name = nil) true end

def next_sequence_value(sequence_name) sql = "UPDATE #{ sequence_name} SET Id=LAST_INSERT_ID(Id+1);" update(sql, "#{sequence_name} Update") select_value("SELECT Id from #{ sequence_name}",'Id') end

end end

Page 67: Introduction to Active Record at MySQL Conference 2007

Ruby on Rails AR Alternatives

Ruby DataMapper

iBatis - rBatis

Page 68: Introduction to Active Record at MySQL Conference 2007

Ruby DataMapperhttp://rubyforge.org/projects/datamapper

class FasterAuthor < DataMapper::Base

set_table_name 'authors'

property :name, :string, :size => 100 property :url, :string, :size => 255 property :is_active?, :boolean property :email, :string, :size => 255 property :hashed_pass, :string, :size => 40 property :created_at, :datetime property :modified_at, :datetime

has_many :posts, :class => 'FasterPost' # :foreign_key => 'post_id'

# prepends HTTP to a URL if necessary def self.prepend_http(url = '') if url and url != '' and not(url =~ /^http/i) url = 'http://' + url end return url end

end

Page 69: Introduction to Active Record at MySQL Conference 2007

iBatis - rBatisiBatis for Ruby (RBatis) is a port of Apache's iBatis library to Ruby and Ruby on Rails. It is an O/R-mapper that allows for complete customization of SQL. http://ibatis.apache.org

Not Very DRY / Rails Like

Page 70: Introduction to Active Record at MySQL Conference 2007

Drink the Kool aid?

Page 71: Introduction to Active Record at MySQL Conference 2007

Flickr Photos Used:http://flickr.com/photos/brraveheart/114402291/http://flickr.com/photos/bright/253175260/http://flickr.com/photos/good_day/63617697/http://flickr.com/photos/rickharris/416150393/http://flickr.com/photos/babasteve/3322247/http://flickr.com/photos/olivander/28058685/http://flickr.com/photos/brraveheart/44052308/http://flickr.com/photos/ednothing/142393509/http://flickr.com/photos/alltheaces/87505524/http://flickr.com/photos/alfr3do/7436142/http://flickr.com/photos/gdominici/57975123/http://flickr.com/photos/josefstuefer/72512671/http://flickr.com/photos/uqbar/105440294/http://flickr.com/photos/auntiep/17135231/http://flickr.com/photos/einsame_spitze/406992131/http://flickr.com/photos/beija-flor/63758047/http://flickr.com/photos/amerune/174617912/http://flickr.com/photos/hungry_i/47938311/http://flickr.com/photos/santos/13952912/http://flickr.com/photos/supermietzi/179962496/http://flickr.com/photos/traveller2020/206931940/http://flickr.com/photos/ko_an/318906221/

http://flickr.com/photos/ryangreenberg/57722319/http://flickr.com/photos/benandliz/11065337/http://flickr.com/photos/gaspi/12944421/http://flickr.com/photos/thomashawk/221827536/http://flickr.com/photos/brianboulos/7707518/http://flickr.com/photos/ross/28330560/http://flickr.com/photos/emdot/45249090/http://flickr.com/photos/farhang/428136695/http://flickr.com/photos/belljar/67877047/http://flickr.com/photos/pulpolux/34545782/http://flickr.com/photos/monkeyc/107979135/http://flickr.com/photos/pedrosimoes7/449314732/http://flickr.com/photos/dincordero/405452471/http://flickr.com/photos/andidfl/203883534/http://flickr.com/photos/ivanomak/434387836/http://flickr.com/photos/nrvica/23858419/http://flickr.com/photos/thespeak/137012632/http://flickr.com/photos/thowi/31533027/http://flickr.com/photos/thelifeofbryan/468557520/http://flickr.com/photos/eecue/289208982/http://flickr.com/photos/estherase/14110154/http://flickr.com/photos/ehnmark/118117670/

Page 72: Introduction to Active Record at MySQL Conference 2007

Introduction to Active RecordEvan ‘Rabble’ Henshaw-Plath

[email protected] - Yahoo! Brickhouseanarchogeek.com - testingrails.com

Questions?