Introduction to
 Active Record
    Evan ‘Rabble’ Henshaw-Plath
evan@protest.net - Yahoo! Brickhouse
 anarchogeek.com - tes...
Active Record is a
    Design Pattern
An object that wraps a row in a database table
or view, encapsulates the database ac...
Active Record
          the Pattern
                 Person
            last_name
            first_name
            depend...
One Class Per Table
The Model Code                    The Database
class User < ActiveRecord::Base   CREATE TABLE `users` ...
One Object Per Row
There Are Other Ways
      To Do it
Active Record is
just one ‘Data Source
Architectural Pattern’

• Table Data Gateway
• ...
Standard Active Record

• Direct mapping to the DB
 • Class to table
 • Object to row
• Simple, no relationship between ob...
ActiveRecord
       the ruby library
Active Record is
a library built
for Ruby on Rails.

Makes CRUD Easy
Create
Read
Upda...
ActiveRecord
     the ruby library
I have never seen an Active Record
    implementation as complete
or as useful as rails...
Rails’ ActiveRecord
• DRY Conventions & Assumptions
• Validations
• Before and after filters
• Database Agnostic (mostly)
•...
What Active
Record Likes
• mapping class names to
  table names
• pluralized table names
• integer primary keys
• classnam...
Active Record
 Doesn’t Like
 • views
 • stored methods
 • foreign key constraints
 • cascading commits
 • split or cluster...
The Basics
./app/models/user.rb                Loading a user
class User < ActiveRecord::Base
                            ...
The Find Method
Find is the primary method of Active Record

Examples:
	   User.find(23)
	   User.find(:first)
	   User.find(:...
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,...
Understanding Find

Model#find(:all, { parameters hash }

What Find Does:
	 * generates sql
	 * executes sql
	 * returns an...
Find with :conditions
:conditions - An SQL fragment like
	 "administrator = 1" or [ "user_name = ?", username ].

Student....
Doing it Securely
class User < ActiveRecord::Base
  def self.authenticate_unsafely(user_name, password)
   find(:first, :con...
Order By

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

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

SQL Exec...
Group By

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

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

:offset- An integ...
Joins

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

Depreciated Find’s
find_first
find_all
find_on_con...
Associations

The Four Primary Associations
belongs_to
has_one
has_many
has_and_belongs_to_many
class Project < ActiveReco...
Associations

One to One
	 has_one & belongs_to
Many to One
	 has_many & belongs_to
Many to Many
	 has_and_belongs_to_many...
One to One
Use has_one in the base, and belongs_to in the
associated model.

 class Employee < ActiveRecord::Base
  has_on...
One To One Example
>> joe_employee = Employee.find_by_first_name('joe')
SELECT * FROM employees
	    WHERE (employees.`first_...
belongs_to
One to One Relationship.
Use belong to when the foreign key is in THIS table.

 •   Post#author (similar to Aut...
Defining belongs_to
class Employee < ActiveRecord::Base
    belongs_to :firm, :foreign_key => "client_of"

    belongs_to :a...
has_one
One to One Relationship.
Use has_one when the foreign key is in the OTHER table.
 •   Account#beneficiary (similar ...
Defining has_one
class Employee < ActiveRecord::Base
 # destroys the associated credit card
 has_one :credit_card, :depende...
One to Many
One-to-many
Use has_many in the base, and belongs_to in
the associated model.

class Manager < ActiveRecord::B...
One to Many
>> benevolent_dictator = Manager.find(:first, :conditions => ['name = "DHH"'])
	 SELECT * FROM managers WHERE (n...
has_many
                  Augmenting the Model
•   Firm#clients (similar to Clients.find :all, :conditions =>
    "firm_id ...
has_many
•   Firm#client.clear
•   Firm#clients.empty? (similar to firm.clients.size
    == 0)
•   Firm#clients.size (simil...
has_many examples
class Employee < ActiveRecord::Base
 has_many :comments, :order => "posted_on"
 has_many :comments, :inc...
Many to Many
    Simple Joiner Table
has_and_belongs_to_many

      Joiner Model
   has_many :through
has_and_belongs_to_many
  The Simple Joiner Table Way
has_and_belongs_to_many
neglected
    by
rails-core
has_and_belongs_to_many
                Augmenting the Model
  •   Developer#projects
  •   Developer#projects<<
  •   Dev...
has_and_belongs_to_many

 •   Developer#projects.empty?
 •   Developer#projects.size
 •   Developer#projects.find(id) # Als...
habtm example
create_table :developers do |t|
 t.column :name, :string
 t.column :created_at, :datetime
end

create_table ...
habtm example
>> d = Developer.find(1)

    SELECT * FROM developers WHERE (developers.`id` = 1)
=> #<Developer:0x32bc7dc @...
has_many :through

    DHH’s
 One True Way
of Many to Many
has_many :through

Full Joiner Model
has_many :through
  class Appearance < ActiveRecord::Base
   belongs_to :dancer
   belongs_to :movie
  end

  class Dancer...
Validations
class User < ActiveRecord::Base

 validates_confirmation_of :login, :password

 validates_confirmation_of :email...
Validations
• Keeping Data Clean
• In object validation of fields, calculated
  validations
• Instead of key constraints
• ...
But Wait?

• Aren’t format, presence, relationship
  validations supposed to be the database’s
  job?
• Traditionally, yes...
But Why?

• Validations  Constraints are Business Logic
• Business logic should be in the model
• It makes things easy
• E...
Data Integrity?
• It’s still possible to do constraints in the db
• But it’s not as necessary
• Validations are constraint...
What AR Returns?
• Enumerable Objects (kind of like arrays)
• Preselects and instantiates objects
• Nifty methods: to_yaml...
Output Formats
ruby - inspect                                to_yaml
#Employee:0x36926a4                          --- !rub...
Before  After
                            Callbacks
                                                             * (-) sav...
Security
Special Fields
* created_at     * #{table_name}_count
                 * position
* created_on
                 * parent_i...
Active Record Tricks
Drink the Kool aid?
Flickr Photos Used:
http://flickr.com/photos/brraveheart/114402291/
                                                    htt...
Questions?

 Introduction to
  Active Record
    Evan ‘Rabble’ Henshaw-Plath
evan@protest.net - Yahoo! Brickhouse
 anarcho...
Upcoming SlideShare
Loading in...5
×

Introduction to Active Record - Silicon Valley Ruby Conference 2007

40,153

Published on

An introduction to the Ruby on Rails library ActiveRecord presented at the SD Forum Silicon Valley Ruby on Rails conference Apirl 21st 2007.

Published in: Economy & Finance, Technology
7 Comments
90 Likes
Statistics
Notes
No Downloads
Views
Total Views
40,153
On Slideshare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
2,669
Comments
7
Likes
90
Embeds 0
No embeds

No notes for slide

Introduction to Active Record - Silicon Valley Ruby Conference 2007

  1. 1. Introduction to Active Record Evan ‘Rabble’ Henshaw-Plath evan@protest.net - Yahoo! Brickhouse anarchogeek.com - testingrails.com
  2. 2. 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.
  3. 3. Active Record the Pattern Person last_name first_name dependents_count insert update get_exemption is_flagged_for_audit? get_taxable_earnings? Active Record uses the most obvious approach, putting data access logic in the domain object. - Martin Fowler
  4. 4. One Class Per Table The Model Code The Database class User < ActiveRecord::Base CREATE TABLE `users` ( `id` int(11) NOT NULL auto_increment, end `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;
  5. 5. One Object Per Row
  6. 6. There Are Other Ways To Do it Active Record is just one ‘Data Source Architectural Pattern’ • Table Data Gateway • Row Data Gateway • Data Mapper • The Anti-Patterns
  7. 7. 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
  8. 8. ActiveRecord the ruby library Active Record is a library built for Ruby on Rails. Makes CRUD Easy Create Read Update Delete
  9. 9. ActiveRecord the ruby library I have never seen an Active Record implementation as complete or as useful as rails. - Martin Fowler
  10. 10. Rails’ ActiveRecord • DRY Conventions & Assumptions • Validations • Before and after filters • Database Agnostic (mostly) • Migrations • Model relationships • has_many, belongs_to, etc...
  11. 11. What Active Record Likes • mapping class names to table names • pluralized table names • integer primary keys • classname_id foreign keys • simple schemas • single table inheritance
  12. 12. Active Record Doesn’t Like • views • stored methods • foreign key constraints • cascading commits • split or clustered db’s • enums
  13. 13. The Basics ./app/models/user.rb Loading a user class User < ActiveRecord::Base >> user_obj = User.find(2) end => #<User:0x352e8bc @attributes= {"salt"=>"d9ef...", The SQL Log "updated_at"=>"2007-04-19 10:49:15", "crypted_password"=>"9c1...", User Load (0.003175) "id"=>"2", SELECT * FROM users "remember_token"=>"a8d...", WHERE (users.id = 2) LIMIT 1 "login"=>"rabble", "created_at"=>"2007-04-19 10:49:15", "email"=>"evan@protest.net"}>
  14. 14. 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
  15. 15. 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.
  16. 16. 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
  17. 17. 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);
  18. 18. 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 (Next Version of Rails) def self.authenticate_safely_simply(user_name, password) find(:first, :conditions => { :user_name => user_name, :password => password }) end end
  19. 19. 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;
  20. 20. 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;
  21. 21. 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;
  22. 22. 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 * FROM users GROUP BY graduating_class; Returns read only objects unless you say :readonly => false
  23. 23. Alternative Finds find_by_sql find_by_attribute_and_attribute2 find_or_create Depreciated Find’s find_first find_all find_on_conditions
  24. 24. Associations The Four Primary Associations belongs_to has_one has_many has_and_belongs_to_many class Project < ActiveRecord::Base belongs_to :portfolio has_one :project_manager has_many :milestones has_and_belongs_to_many :categories end
  25. 25. Associations 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
  26. 26. 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
  27. 27. 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.office SELECT * 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.employee SELECT * 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"}>
  28. 28. belongs_to One 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;
  29. 29. Defining belongs_to class 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 => true end
  30. 30. has_one One to One Relationship. Use has_one when the foreign key is in the OTHER table. • 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)
  31. 31. Defining has_one class 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
  32. 32. One to Many One-to-many Use has_many in the base, and belongs_to in the associated model. class Manager < ActiveRecord::Base has_many :employees end class Employee < ActiveRecord::Base belongs_to :manager # foreign key - manager_id end
  33. 33. One to Many >> 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"}>]
  34. 34. has_many Augmenting the Model • Firm#clients (similar to Clients.find :all, :conditions => "firm_id = #{id}") • Firm#clients<< • Firm#clients.delete • Firm#client_ids • Firm#client_ids= • Firm#clients=
  35. 35. 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)
  36. 36. 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
  37. 37. Many to Many Simple Joiner Table has_and_belongs_to_many Joiner Model has_many :through
  38. 38. has_and_belongs_to_many The Simple Joiner Table Way
  39. 39. has_and_belongs_to_many neglected by rails-core
  40. 40. has_and_belongs_to_many Augmenting the Model • Developer#projects • Developer#projects<< • Developer#projects.delete • Developer#projects= • Developer#projects_ids • Developer#projects_ids= • Developer#clear
  41. 41. 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)
  42. 42. 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
  43. 43. 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}>]
  44. 44. has_many :through DHH’s One True Way of Many to Many
  45. 45. has_many :through Full Joiner Model
  46. 46. has_many :through class Appearance < ActiveRecord::Base belongs_to :dancer belongs_to :movie end class Dancer < ActiveRecord::Base has_many :appearances, :dependent => true has_many :movies, :through => :appearances end class Movie < ActiveRecord::Base has_many :appearances, :dependent => true has_many :dancers, :through => :appearances end
  47. 47. 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,})/i, :on = :create end
  48. 48. 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...
  49. 49. 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
  50. 50. 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
  51. 51. 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
  52. 52. What AR Returns? • Enumerable Objects (kind of like arrays) • Preselects and instantiates objects • Nifty methods: to_yaml, to_xml, to_json
  53. 53. Output Formats ruby - inspect to_yaml #Employee:0x36926a4 --- !ruby/object:Employee @attributes= attributes: {manager_id=1, manager_id: 1 id=1, id: 1 first_name=joe, first_name: joe last_name=schmo, last_name: schmo created_at=2007-04-21 09:08:59} created_at: 2007-04-21 09:08:59 to_xml to_json ?xml version=1.0 encoding=UTF-8? {attributes: employee {manager_id: 1, created-at id: 1, type=datetime2007-04-21T09:08:59-07:00/ created-at first_name: joe, first-namejoe/first-name last_name: schmo, id type=integer1/id created_at: 2007-04-21 09:08:59}} last-nameschmo/last-name manager-id type=integer1/manager-id /employee
  54. 54. Before After Callbacks * (-) save class Subscription ActiveRecord::Base * (-) valid? before_create :record_signup * (1) before_validation private * (2) before_validation_on_create def record_signup * (-) validate self.signed_up_on = Date.today * (-) validate_on_create end * (3) after_validation end * (4) after_validation_on_create * (5) before_save class Firm ActiveRecord::Base # Destroys the associated clients and * (6) before_create #people when the firm is destroyed * (-) create before_destroy { * (7) after_create |record| Person.destroy_all firm_id = #{record.id} } * (8) after_save before_destroy { |record| Client.destroy_all client_of = #{record.id} } end
  55. 55. Security
  56. 56. Special Fields * created_at * #{table_name}_count * position * created_on * parent_id * updated_at * lft * updated_on * rgt * lock_version * quote * type * template * id
  57. 57. Active Record Tricks
  58. 58. Drink the Kool aid?
  59. 59. Flickr Photos Used: http://flickr.com/photos/brraveheart/114402291/ http://flickr.com/photos/ryangreenberg/57722319/ http://flickr.com/photos/bright/253175260/ http://flickr.com/photos/benandliz/11065337/ http://flickr.com/photos/good_day/63617697/ http://flickr.com/photos/gaspi/12944421/ http://flickr.com/photos/rickharris/416150393/ http://flickr.com/photos/thomashawk/221827536/ http://flickr.com/photos/babasteve/3322247/ http://flickr.com/photos/brianboulos/7707518/ http://flickr.com/photos/olivander/28058685/ http://flickr.com/photos/ross/28330560/ http://flickr.com/photos/brraveheart/44052308/ http://flickr.com/photos/emdot/45249090/ http://flickr.com/photos/ednothing/142393509/ http://flickr.com/photos/farhang/428136695/ http://flickr.com/photos/alltheaces/87505524/ http://flickr.com/photos/belljar/67877047/ http://flickr.com/photos/alfr3do/7436142/ http://flickr.com/photos/pulpolux/34545782/ http://flickr.com/photos/gdominici/57975123/ http://flickr.com/photos/monkeyc/107979135/ http://flickr.com/photos/josefstuefer/72512671/ http://flickr.com/photos/pedrosimoes7/449314732/ http://flickr.com/photos/uqbar/105440294/ http://flickr.com/photos/dincordero/405452471/ http://flickr.com/photos/auntiep/17135231/ http://flickr.com/photos/andidfl/203883534/ http://flickr.com/photos/einsame_spitze/406992131/ http://flickr.com/photos/ivanomak/434387836/ http://flickr.com/photos/beija-flor/63758047/ http://flickr.com/photos/nrvica/23858419/ http://flickr.com/photos/amerune/174617912/ http://flickr.com/photos/thespeak/137012632/ 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/
  60. 60. Questions? Introduction to Active Record Evan ‘Rabble’ Henshaw-Plath evan@protest.net - Yahoo! Brickhouse anarchogeek.com - testingrails.com
  1. Gostou de algum slide específico?

    Recortar slides é uma maneira fácil de colecionar informações para acessar mais tarde.

×