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

Upload: rabble-

Post on 17-Aug-2014

13.180 views

Category:

Economy & Finance


5 download

DESCRIPTION

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

TRANSCRIPT

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?