SlideShare a Scribd company logo
Introduction to ActiveRecord The Rails Object Relational Mapper by Mark Menard, Vita Rara, Inc.
Rails ActiveRecord ActiveRecord is the Object Relational Mapping library that is built into Rails. ActiveRecord is the default ORM used in Rails, but others can be used as well, such as: Data Mapper Sequel ActiveRecord was started by David Heinemeier Hansson the creator of Rails. ActiveRecord has been enhanced and expanded by many developers. ActiveRecord is an implementation of the active record pattern. Rails’ ActiveRecord is a leaky SQL abstraction. © Vita Rara, Inc.
Definition © Vita Rara, Inc. Active Record: An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data. -Martin Fowler, Patterns of Enterprise Application Architecture (page 160)
Rails ActiveRecord ActiveRecord classes and the tables they wrap are referred to as models. ActiveRecord encourages a Model Driven style of development. ActiveRecord encourages a non-anemic model layer. Skinny Controllers Fat Models Rarely a need for a service layer. ActiveRecord can be used as a persistence layer in a Domain Driven Design. © Vita Rara, Inc.
A Leaky Abstraction ActiveRecord will not isolate you from SQL. It’s not Hibernate It’s not JPA It’s not NHibernate It’s not your daddy’s “make SQL go away ORM”. A knowledge of SQL is necessary to succeeding with ActiveRecord. ActiveRecord makes the easy SQL things easy, and makes the hard SQL stuff possible. © Vita Rara, Inc.
Fundamentals One database table maps to one Ruby class Table names are plural and class names are singular Database columns map to attributes, i.e. get and set methods, in the model class Attributes are not defined on the class. Attributes are inferred from the underlying table schema. All tables have an integer primary key called id Database tables are created with migrations   © Vita Rara, Inc.
ActiveRecord Model Example © Vita Rara, Inc. create_table  &quot;persons&quot;   do  |t|  t.string :first_name, last_name t.timestamps  end class  Person < ActiveRecord::Base end p = Person.new p.first_name = ‘Mark’ p.last_name = ‘Menard’ p.save
Working with Legacy Schemas Table name can be set using set_table_name. Views can also be used to adapt to AR conventions Id column can be mapped using “configuration”. Different column names can be mapped with relative ease. Typically attribute names are lowercase with words separated by underscores. first_name updated_at I have personally mapped study caps style tables to Rails defaults. firstName => first_name © Vita Rara, Inc.
CRUD: Create, Read, Update, Delete Create p = Person.create(:first_name => ‘Mark’) p = Person.new(:first_name => ‘Mark’) Read p = Person.find(1) p = Person.find_by_first_name(‘Mark’) Update p.save p.update_attributes(:last_name => ‘Menard’) Delete p.destroy © Vita Rara, Inc.
ActiveRecord::Base.new © Vita Rara, Inc. # Instantiate a new Person, which can be persisted. p  =  Person. new p.save # Instantiate a new Person, with attributes set based on a # Map, which can be persisted. p  =  Person. new (:first_name =>  'Mark' , :last_name =>  'Menard' ) p.save
ActiveRecord::Base.create © Vita Rara, Inc. # Immediated create a record in the database. p  =  Person.create(:first_name =>  'Mark' , :last_name =>  'Menard' ) # This sets the attributes and calls #save on the instance.
Finding Models Built in finders Find the first record: User.find(:first) Find all records of a type: User.find(:all) Find by primary id: User.find(1) Dynamic finders using attributes ActiveRecord can build basic finders by convention based on the attributes of a model. User.find_by_login(‘mark’) © Vita Rara, Inc.
Advanced Finding Because ActiveRecord is a leaky abstraction it provides straight forward ways to access SQL in its finders © Vita Rara, Inc. User.find(:all,  :conditions => [ “login  =   ?  AND password  =   ?” , login, password], :limit =>  10 , :offset =>  10 , :order =>  'login' , :joins =>  'accounts on user.account_id = accounts.id' )
Advanced Finding (con’t) Finders also support: :select :group :include (optimize n+1 queries) © Vita Rara, Inc.
Eager Loading: Avoid N+1 Issue © Vita Rara, Inc. <%  # Don't put code like this in your view. This is for illustration only! # Find and display order summary of all pending orders for an account. orders  =  Order.find_pending_by_account(current_account) %> <% orders.each  do  |order| -%> <%= render :partial =>  'order_header'  %> <!-- This fires off a query for each order! BAD BAD BAD --> <% order.line_items.each  do  |line_item| -%> <%= render :partial =>  'line_item'  %> <%  end  -%> <%  end  -%> <%  # Better would be orders  =  Order.find_pending_by_account(current_account,  :include => [ :line_items ]) %>
Updating Models © Vita Rara, Inc. user  =  User.find( 1 ) user.first_name  =  ‘Mark’ user.save # returns true on success user.last_name  =  ‘Menard’ user.save! # throws an exception if it fails # Immediately update the attributes and call #save # returns true on success user.update_attributes(:first_name =>  'John' ,  :last_name =>  'Doe' ) # Immediately update the attributes and call #save! # throws an exception on failure. user.update_attributes!(:password =>  ‘abccd1234’ )
Transactions Account.transaction do account1.deposit(100) account2.withdraw(100) end © Vita Rara, Inc.
ActiveRecord Associations
ActiveRecord Associations Two primary types of associations: belongs_to has_one / has_many There are others, but they are not commonly used. has_and_belongs_to_many Used to map many-to-many associations. Generally accepted practice is to use a join model. © Vita Rara, Inc.
Association Methods Associations add methods to the class. This is an excellent example of meta-programming. Added methods allow for easy management of the related models. © Vita Rara, Inc.
ActiveRecord Association Examples © Vita Rara, Inc. # Has Many class  Order < ActiveRecord::Base has_many :order_line_items end class  OrderLineItem < ActiveRecord::Base belongs_to :order end # Has One class  Party < ActiveRecord::Base has_one :login_credential end class  LoginCredential < ActiveRecord::Base belongs_to :party end
has_many & belongs_to Used to model one-to-many associations. The belongs_to side has the foreign key. © Vita Rara, Inc. class  Order < ActiveRecord::Base   has_many :line_items end class  LineItem < ActiveRecord::Base   belongs_to :order end create_table :orders  do  |t|   t.string :number end create_table :line_items  do  |t|   t.integer :order_id end
Has Many Examples © Vita Rara, Inc. has_many :comments, :order =>  &quot;posted_on&quot;   has_many :comments, :include => :author  has_many :people, :class_name =>  &quot;Person&quot; ,    :conditions =>  &quot;deleted = 0&quot; , :order =>  &quot;name&quot;   has_many :tracks, :order =>  &quot;position&quot; , :dependent => :destroy  has_many :comments, :dependent => :nullify  has_many :tags, :as => :taggable  has_many :subscribers, :through => :subscriptions, :source => :user  has_many :subscribers, :class_name =>  &quot;Person&quot; , :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'
has_many Methods © Vita Rara, Inc. class  Firm   has_many :clients end firm  =  Firm.find( 1 ) firm.clients firm.clients <<   firm.clients.delete  firm.clients =   firm.client_ids  firm.client_ids =   firm.clients.clear  firm.clients.empty? firm.clients.count  firm.clients.find firm.clients.build(:first_name =>  'Mark' ) # Like Party.new(:firm_id => firm.id) firm.clients.create(:first_name =>  'Mark' ) # Like Party.create(:firm_id => firm.id)
has_and_belongs_to_many Used to model many-to-many associations. © Vita Rara, Inc. create_table :categories_posts, :id => false  do    t.column :category_id, :integer, :null => false    t.column :post_id, :integer, :null => false  end   class  Product < ActiveRecord::Base   has_and_belongs_to_many :categories end class  Category < ActiveRecord::Base   has_and_belongs_to_many :products end product  =  Product.find_by_name(“Mac Book Pro”) category  =  Category.find_by_name(“Laptops”)  product.categories.count # => 0  category.products.count # => 0  product.categories  <<  category  product.categories.count # => 1  category.products.count # => 1
Join Models vs. has_and_belongs_to_many Join models  Are generally preferred. Make the joining table explicit. Allow domain logic to be added to the join model. Allow a more literate style of coding. has_many :foos, :through => :bars  makes it trivial. Commonly has_and_belongs_to_many associations are refactored later to make the join model explicit. Better to just do it up front. © Vita Rara, Inc.
has_many :foos, :through => :bars has_many :through is used to model has_many relationships through a “join” model. © Vita Rara, Inc. class  Blog < ActiveRecord::Base   has_many :subscriptions   has_many :users, :through => :subscriptions end class  User < ActiveRecord::Base has_many :subscriptions has_many :blogs, :through => :subscriptions end class  Subscription < ActiveRecord::Base   belongs_to :blog   belongs_to :user end
Polymorphic Associations Easiest to illustrate by example © Vita Rara, Inc. class  Person < ActiveRecord::Base   has_one :address, :as => :addressable end class  Company < ActiveRecord::Base   has_one :address, :as => :addressable end class  Address < ActiveRecord::Base   belongs_to :addressable, :polymorphic => true end create_table :addresses  do  |t|   # ...   t.integer :addressable_id   t.string  :addressable_type end
ActiveRecord Validations Keeping Your Data Safe
Validation Validations are rules in your model objects to help protect the integrity of your data Validation is invoked by the #save method. Save returns true if validations pass and false otherwise. If you invoke #save! then a RecordInvalid exception is raised if the object is not valid. Use save(false) if you need to turn off validation  © Vita Rara, Inc.
Validation Callbacks #validate Called before a model is written to the database, either on initial save, or on updates. #validate_on_create Called before a model is inserted into the database. #validate_on_update Called before an existing model is updated in the database. © Vita Rara, Inc.
Validation Callbacks (cont) © Vita Rara, Inc. class  Person < ActiveRecord::Base  def   validate   puts “validate invoked”  end   def   validate_on_create   puts “validate_on_create invoked”  end   def   validate_on_update   puts “validate_on_update invoked”  end   end   peter  =  Person.create(:name => “Peter”)  # => peter.validate and peter.validate_on_create invoked  peter.last_name  =  “Forsberg”  peter.save # => peter.validate_on_update invoked
Declarative Validations © Vita Rara, Inc. Rails contains a large number of declarative validations that are applied to classes by convention. Declarative validations free developers from the drudgery of most model validation.
validates_presence_of Used to denote required attributes. © Vita Rara, Inc. class  Person < ActiveRecord::Base   validates_presence_of :first_name   validates_presence_of :last_name end p  =  Person. new p.valid? #=> false p.first_name  =   'Mark' p.last_name  =   'Menard' p.valid? #=> true
validates_uniqueness_of Ensures that the value of an attribute is unique in the database. Can be constrained to work subsets of the data. © Vita Rara, Inc. class  User < ActiveRecord::Base belongs_to :account   validates_uniqueness_of :login, :scope => [ :account ] end account = Account.find(1) user_1  =  account.users.create(:login =>  'mark' ) user_2  =  account.users.create!(:login =>  'mark' ) #=> Throws InvalidRecord exceptoion
validates_numericality_of Ensures that an attribute is a number. Can be constrained to integral values. © Vita Rara, Inc. class  User < ActiveRecord::Base   validates_numericality_of :number, :integer_only => true end User.create!(:number =>  'some number' ) #=> Throws Invalid
validates_length_of Ensures an attribute is the proper length © Vita Rara, Inc. class  User < ActiveRecord::Base   validates_length_of :login, :within =>  3 .. 20   validates_length_of :password, :is =>  8   validates_length_of :name, :minimum =>  3 end
validates_format_of Ensures the format of an attribute matches regular expression. Can be used to validate email addresses. © Vita Rara, Inc. class  User < ActiveRecord::Base   validates_format_of :email, :with =>  /^[\w\d]+$/ end
validates_inclusion_of & validates_exclusion_of Ensures that a value is or is not in a collection of options. © Vita Rara, Inc. class  User < ActiveRecord::Base   validates_inclusion_of :gender, :in =>  %w( male female ) ,  :message =>  &quot;Oh really....&quot; validates_exclusion_of :login, :in =>  %w( root admin super ) ,  :message =>  &quot;Tisk tisk...&quot; end
validates_associated Ensures that an associated model is valid prior to saving. © Vita Rara, Inc. class  User < ActiveRecord::Base   belongs_to :account   validates_associated :account, :on => :create end class  Account < ActiveRecord::Base   validates_presence_of :name end user  =  User. new (:login =>  'mark' , :name =>  'Mark Menard' ) user.account  =  Account. new  # invalid missing name user.save! #=> Throws RecordInvalid exception.
Other Declarative Validations validates_acceptance_of  validates_confirmation_of  validates_each  validates_size_of © Vita Rara, Inc. You can also create your own declarative validations that match your problem domain.
Using Validation Callbacks Sometimes validation is more complex than the declarative validations can handle. Validation may relate to the semantics of your problem domain. Validation may relate to more than one attribute. © Vita Rara, Inc. class  Account   validate :does_domain_exist     private     def   does_domain_exist   Resolv.getaddress(self.domain_name)   rescue   errors.add(:domain_name,  'Domain name does not exist.' )   end end
Using Validation Callbacks Class methods for defining validation call backs: validate :method_name validate_on_update :method_name validate_on_create :method_name Instance methods for defining validations: validate validate_on_update validate_on_create © Vita Rara, Inc.
Model Life Cycle
New Model Callbacks ActiveRecord calls these methods prior to saving a new record: before_validation before_validation_on_create validation is performed after_validation after_validation_on_create before_save before_create ActiveRecord saves the record after_create after_save © Vita Rara, Inc.
Existing Model Callbacks ActiveRecord calls these methods prior to saving an existing record before_validation ActiveRecord performs validation after_validation before_save before_update ActiveRecord saves the record after_update after_save © Vita Rara, Inc.
Destroy Model Callbacks ActiveRecord calls these methods when destroying a model: before_destroy ActiveRecord performs the DELETE after_destroy © Vita Rara, Inc.
Callback Use Cases Cleaning up attributes prior to saving Starting followup processes Sending notifications Geocoding Paranoia: Don’t delete anything just mark it deleted. Clean up associated files, avatars, other assets. © Vita Rara, Inc.
Cleaning up Attributes Prior to Saving © Vita Rara, Inc. class  CreditCard   before_validation :cleanup_number     private     def   cleanup_number   self.number  =  number.gsub( /[^0-9]/ ,  &quot;&quot; ) true  # I like to be explicit   end end
Observers
Observers Observers allow you to create classes that observe changes in your Models. Observers allow you classes to focus on a single responsibility. Observers can hook onto the standard rails life cycle call backs. © Vita Rara, Inc.
Creating an Audit Trail with an Observer © Vita Rara, Inc. # in config/environment.rb config.active_record_observers  =  [ :auditor ] # in auditor.rb class  Auditor < ActiveRecord::Observer   observe User     def   after_create  (model)   log_info( &quot;New #{model.class.name} created.&quot; , model)   end     def   after_update  (model)   log_info( &quot;Update #{model.class.name}&quot; , model)   end     def   after_destroy  (model)   log_info( &quot;Destroy #{model.class.name}&quot; , model)   end     private     def   log_info  (model, info)   log.info(info)   log.info(model.inspect)   end end
Shameless Self Promotion
Ruby and Rails Training One day to three day programs. Introduction to Ruby Advanced Ruby Introduction to Rails Advanced Rails Test Driven Development Behavior Driven Development Test Anything with Cucumber Advanced Domain Modeling with ActiveRecord Domain Driven Development with Rails © Vita Rara, Inc.
Ruby on Rails Consulting Full Life Cycle Project Development Inception Implementation Deployment Long Term Support Ruby on Rails Mentoring Get your team up to speed using Rails © Vita Rara, Inc.
Contact Information Mark Menard [email_address] http://www.vitarara.net / 518 369 7356 © Vita Rara, Inc.

More Related Content

What's hot (20)

PPTX
React Hooks
Joao Marins
 
PDF
Examen febrero 2017-2018_daw_daw_solucion_ (1)
jomadega1
 
PPT
7 rest
youssef kotti
 
PPTX
Hadoop Oozie
Madhur Nawandar
 
PDF
BigData_Chp5: Putting it all together
Lilia Sfaxi
 
PDF
laravel.sillo.org-Cours Laravel 10 les bases installation et organisation.pdf
HeartKing10
 
PPTX
java Servlet technology
Tanmoy Barman
 
PPTX
Basic Concept of Node.js & NPM
Bhargav Anadkat
 
PPTX
Multi threading
gndu
 
PPTX
MongoDB - Aggregation Pipeline
Jason Terpko
 
PDF
Data Types In PHP
Mark Niebergall
 
PDF
Java entreprise edition et industrialisation du génie logiciel par m.youssfi
ENSET, Université Hassan II Casablanca
 
PDF
AngularJS: an introduction
Luigi De Russis
 
PDF
Introduction to Node.js
Rob O'Doherty
 
PPT
Knowledge Sharing : Java Servlet
Fahmi Jafar
 
PPTX
Workshop spring session 2 - La persistance au sein des applications Java
Antoine Rey
 
PPTX
Programmation orientée objet avancée
Mahfoud EL HOUDAIGUI
 
PPT
SOLID Design Principles
Andreas Enbohm
 
DOCX
ANGULAR JS LAB MANUAL(final) vtu2021 sch
kannikadg
 
React Hooks
Joao Marins
 
Examen febrero 2017-2018_daw_daw_solucion_ (1)
jomadega1
 
Hadoop Oozie
Madhur Nawandar
 
BigData_Chp5: Putting it all together
Lilia Sfaxi
 
laravel.sillo.org-Cours Laravel 10 les bases installation et organisation.pdf
HeartKing10
 
java Servlet technology
Tanmoy Barman
 
Basic Concept of Node.js & NPM
Bhargav Anadkat
 
Multi threading
gndu
 
MongoDB - Aggregation Pipeline
Jason Terpko
 
Data Types In PHP
Mark Niebergall
 
Java entreprise edition et industrialisation du génie logiciel par m.youssfi
ENSET, Université Hassan II Casablanca
 
AngularJS: an introduction
Luigi De Russis
 
Introduction to Node.js
Rob O'Doherty
 
Knowledge Sharing : Java Servlet
Fahmi Jafar
 
Workshop spring session 2 - La persistance au sein des applications Java
Antoine Rey
 
Programmation orientée objet avancée
Mahfoud EL HOUDAIGUI
 
SOLID Design Principles
Andreas Enbohm
 
ANGULAR JS LAB MANUAL(final) vtu2021 sch
kannikadg
 

Similar to Intro to Rails ActiveRecord (20)

ODP
Ruby on rails
Mohit Jain
 
PPT
Boston Computing Review - Ruby on Rails
John Brunswick
 
PDF
OSDC 2009 Rails Turtorial
Yi-Ting Cheng
 
ODP
Practical catalyst
dwm042
 
PPT
What's new in Rails 2?
brynary
 
PPT
Intro to Ruby on Rails
Mark Menard
 
PDF
Extending MySQL Enterprise Monitor
Mark Leith
 
ODP
DynamicRecord Presentation
linoj
 
PDF
Nhibernatethe Orm For Net Platform 1226744632929962 8
Nicolas Thon
 
PDF
NHibernate (The ORM For .NET Platform)
Samnang Chhun
 
PPT
Debugging and Error handling
Suite Solutions
 
PPT
Jasig Rubyon Rails
Paul Pajo
 
PDF
Compass Framework
Lukas Vlcek
 
PDF
Building Web Interface On Rails
Wen-Tien Chang
 
PPT
Framework
Nguyen Linh
 
ODP
Grails 0.3-SNAPSHOT Presentation WJAX 2006 English
Sven Haiges
 
PDF
Intro Open Social and Dashboards
Atlassian
 
PPT
WordPress development paradigms, idiosyncrasies and other big words
TomAuger
 
PDF
Introduction to Active Record at MySQL Conference 2007
Rabble .
 
PDF
Rails 2.3 and Rack - NHRuby Feb 2009
bturnbull
 
Ruby on rails
Mohit Jain
 
Boston Computing Review - Ruby on Rails
John Brunswick
 
OSDC 2009 Rails Turtorial
Yi-Ting Cheng
 
Practical catalyst
dwm042
 
What's new in Rails 2?
brynary
 
Intro to Ruby on Rails
Mark Menard
 
Extending MySQL Enterprise Monitor
Mark Leith
 
DynamicRecord Presentation
linoj
 
Nhibernatethe Orm For Net Platform 1226744632929962 8
Nicolas Thon
 
NHibernate (The ORM For .NET Platform)
Samnang Chhun
 
Debugging and Error handling
Suite Solutions
 
Jasig Rubyon Rails
Paul Pajo
 
Compass Framework
Lukas Vlcek
 
Building Web Interface On Rails
Wen-Tien Chang
 
Framework
Nguyen Linh
 
Grails 0.3-SNAPSHOT Presentation WJAX 2006 English
Sven Haiges
 
Intro Open Social and Dashboards
Atlassian
 
WordPress development paradigms, idiosyncrasies and other big words
TomAuger
 
Introduction to Active Record at MySQL Conference 2007
Rabble .
 
Rails 2.3 and Rack - NHRuby Feb 2009
bturnbull
 
Ad

More from Mark Menard (14)

PDF
Let's Do Some Upfront Design - WindyCityRails 2014
Mark Menard
 
PDF
A Tour of Wyriki
Mark Menard
 
PDF
Small Code - RailsConf 2014
Mark Menard
 
PDF
Small Code - Ruby on Ales 2014
Mark Menard
 
PDF
Write Small Things (Code)
Mark Menard
 
PDF
JRuby 6 Years in Production
Mark Menard
 
PDF
Conference of Grand Masters Tech Talk 2013
Mark Menard
 
KEY
Startup Lessons Learned
Mark Menard
 
PDF
Mobile Platforms and App Development
Mark Menard
 
KEY
Ruby on Rails Training - Module 2
Mark Menard
 
KEY
Ruby on Rails Training - Module 1
Mark Menard
 
KEY
Introduction to Ruby
Mark Menard
 
PPT
Behavior Driven Development with Rails
Mark Menard
 
PPT
JRuby in a Java World
Mark Menard
 
Let's Do Some Upfront Design - WindyCityRails 2014
Mark Menard
 
A Tour of Wyriki
Mark Menard
 
Small Code - RailsConf 2014
Mark Menard
 
Small Code - Ruby on Ales 2014
Mark Menard
 
Write Small Things (Code)
Mark Menard
 
JRuby 6 Years in Production
Mark Menard
 
Conference of Grand Masters Tech Talk 2013
Mark Menard
 
Startup Lessons Learned
Mark Menard
 
Mobile Platforms and App Development
Mark Menard
 
Ruby on Rails Training - Module 2
Mark Menard
 
Ruby on Rails Training - Module 1
Mark Menard
 
Introduction to Ruby
Mark Menard
 
Behavior Driven Development with Rails
Mark Menard
 
JRuby in a Java World
Mark Menard
 
Ad

Intro to Rails ActiveRecord

  • 1. Introduction to ActiveRecord The Rails Object Relational Mapper by Mark Menard, Vita Rara, Inc.
  • 2. Rails ActiveRecord ActiveRecord is the Object Relational Mapping library that is built into Rails. ActiveRecord is the default ORM used in Rails, but others can be used as well, such as: Data Mapper Sequel ActiveRecord was started by David Heinemeier Hansson the creator of Rails. ActiveRecord has been enhanced and expanded by many developers. ActiveRecord is an implementation of the active record pattern. Rails’ ActiveRecord is a leaky SQL abstraction. © Vita Rara, Inc.
  • 3. Definition © Vita Rara, Inc. Active Record: An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data. -Martin Fowler, Patterns of Enterprise Application Architecture (page 160)
  • 4. Rails ActiveRecord ActiveRecord classes and the tables they wrap are referred to as models. ActiveRecord encourages a Model Driven style of development. ActiveRecord encourages a non-anemic model layer. Skinny Controllers Fat Models Rarely a need for a service layer. ActiveRecord can be used as a persistence layer in a Domain Driven Design. © Vita Rara, Inc.
  • 5. A Leaky Abstraction ActiveRecord will not isolate you from SQL. It’s not Hibernate It’s not JPA It’s not NHibernate It’s not your daddy’s “make SQL go away ORM”. A knowledge of SQL is necessary to succeeding with ActiveRecord. ActiveRecord makes the easy SQL things easy, and makes the hard SQL stuff possible. © Vita Rara, Inc.
  • 6. Fundamentals One database table maps to one Ruby class Table names are plural and class names are singular Database columns map to attributes, i.e. get and set methods, in the model class Attributes are not defined on the class. Attributes are inferred from the underlying table schema. All tables have an integer primary key called id Database tables are created with migrations © Vita Rara, Inc.
  • 7. ActiveRecord Model Example © Vita Rara, Inc. create_table &quot;persons&quot; do |t| t.string :first_name, last_name t.timestamps end class Person < ActiveRecord::Base end p = Person.new p.first_name = ‘Mark’ p.last_name = ‘Menard’ p.save
  • 8. Working with Legacy Schemas Table name can be set using set_table_name. Views can also be used to adapt to AR conventions Id column can be mapped using “configuration”. Different column names can be mapped with relative ease. Typically attribute names are lowercase with words separated by underscores. first_name updated_at I have personally mapped study caps style tables to Rails defaults. firstName => first_name © Vita Rara, Inc.
  • 9. CRUD: Create, Read, Update, Delete Create p = Person.create(:first_name => ‘Mark’) p = Person.new(:first_name => ‘Mark’) Read p = Person.find(1) p = Person.find_by_first_name(‘Mark’) Update p.save p.update_attributes(:last_name => ‘Menard’) Delete p.destroy © Vita Rara, Inc.
  • 10. ActiveRecord::Base.new © Vita Rara, Inc. # Instantiate a new Person, which can be persisted. p = Person. new p.save # Instantiate a new Person, with attributes set based on a # Map, which can be persisted. p = Person. new (:first_name => 'Mark' , :last_name => 'Menard' ) p.save
  • 11. ActiveRecord::Base.create © Vita Rara, Inc. # Immediated create a record in the database. p = Person.create(:first_name => 'Mark' , :last_name => 'Menard' ) # This sets the attributes and calls #save on the instance.
  • 12. Finding Models Built in finders Find the first record: User.find(:first) Find all records of a type: User.find(:all) Find by primary id: User.find(1) Dynamic finders using attributes ActiveRecord can build basic finders by convention based on the attributes of a model. User.find_by_login(‘mark’) © Vita Rara, Inc.
  • 13. Advanced Finding Because ActiveRecord is a leaky abstraction it provides straight forward ways to access SQL in its finders © Vita Rara, Inc. User.find(:all, :conditions => [ “login = ? AND password = ?” , login, password], :limit => 10 , :offset => 10 , :order => 'login' , :joins => 'accounts on user.account_id = accounts.id' )
  • 14. Advanced Finding (con’t) Finders also support: :select :group :include (optimize n+1 queries) © Vita Rara, Inc.
  • 15. Eager Loading: Avoid N+1 Issue © Vita Rara, Inc. <% # Don't put code like this in your view. This is for illustration only! # Find and display order summary of all pending orders for an account. orders = Order.find_pending_by_account(current_account) %> <% orders.each do |order| -%> <%= render :partial => 'order_header' %> <!-- This fires off a query for each order! BAD BAD BAD --> <% order.line_items.each do |line_item| -%> <%= render :partial => 'line_item' %> <% end -%> <% end -%> <% # Better would be orders = Order.find_pending_by_account(current_account, :include => [ :line_items ]) %>
  • 16. Updating Models © Vita Rara, Inc. user = User.find( 1 ) user.first_name = ‘Mark’ user.save # returns true on success user.last_name = ‘Menard’ user.save! # throws an exception if it fails # Immediately update the attributes and call #save # returns true on success user.update_attributes(:first_name => 'John' , :last_name => 'Doe' ) # Immediately update the attributes and call #save! # throws an exception on failure. user.update_attributes!(:password => ‘abccd1234’ )
  • 17. Transactions Account.transaction do account1.deposit(100) account2.withdraw(100) end © Vita Rara, Inc.
  • 19. ActiveRecord Associations Two primary types of associations: belongs_to has_one / has_many There are others, but they are not commonly used. has_and_belongs_to_many Used to map many-to-many associations. Generally accepted practice is to use a join model. © Vita Rara, Inc.
  • 20. Association Methods Associations add methods to the class. This is an excellent example of meta-programming. Added methods allow for easy management of the related models. © Vita Rara, Inc.
  • 21. ActiveRecord Association Examples © Vita Rara, Inc. # Has Many class Order < ActiveRecord::Base has_many :order_line_items end class OrderLineItem < ActiveRecord::Base belongs_to :order end # Has One class Party < ActiveRecord::Base has_one :login_credential end class LoginCredential < ActiveRecord::Base belongs_to :party end
  • 22. has_many & belongs_to Used to model one-to-many associations. The belongs_to side has the foreign key. © Vita Rara, Inc. class Order < ActiveRecord::Base has_many :line_items end class LineItem < ActiveRecord::Base belongs_to :order end create_table :orders do |t| t.string :number end create_table :line_items do |t| t.integer :order_id end
  • 23. Has Many Examples © Vita Rara, Inc. has_many :comments, :order => &quot;posted_on&quot; has_many :comments, :include => :author has_many :people, :class_name => &quot;Person&quot; , :conditions => &quot;deleted = 0&quot; , :order => &quot;name&quot; has_many :tracks, :order => &quot;position&quot; , :dependent => :destroy has_many :comments, :dependent => :nullify has_many :tags, :as => :taggable has_many :subscribers, :through => :subscriptions, :source => :user has_many :subscribers, :class_name => &quot;Person&quot; , :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'
  • 24. has_many Methods © Vita Rara, Inc. class Firm has_many :clients end firm = Firm.find( 1 ) firm.clients firm.clients << firm.clients.delete firm.clients = firm.client_ids firm.client_ids = firm.clients.clear firm.clients.empty? firm.clients.count firm.clients.find firm.clients.build(:first_name => 'Mark' ) # Like Party.new(:firm_id => firm.id) firm.clients.create(:first_name => 'Mark' ) # Like Party.create(:firm_id => firm.id)
  • 25. has_and_belongs_to_many Used to model many-to-many associations. © Vita Rara, Inc. create_table :categories_posts, :id => false do t.column :category_id, :integer, :null => false t.column :post_id, :integer, :null => false end class Product < ActiveRecord::Base has_and_belongs_to_many :categories end class Category < ActiveRecord::Base has_and_belongs_to_many :products end product = Product.find_by_name(“Mac Book Pro”) category = Category.find_by_name(“Laptops”) product.categories.count # => 0 category.products.count # => 0 product.categories << category product.categories.count # => 1 category.products.count # => 1
  • 26. Join Models vs. has_and_belongs_to_many Join models Are generally preferred. Make the joining table explicit. Allow domain logic to be added to the join model. Allow a more literate style of coding. has_many :foos, :through => :bars makes it trivial. Commonly has_and_belongs_to_many associations are refactored later to make the join model explicit. Better to just do it up front. © Vita Rara, Inc.
  • 27. has_many :foos, :through => :bars has_many :through is used to model has_many relationships through a “join” model. © Vita Rara, Inc. class Blog < ActiveRecord::Base has_many :subscriptions has_many :users, :through => :subscriptions end class User < ActiveRecord::Base has_many :subscriptions has_many :blogs, :through => :subscriptions end class Subscription < ActiveRecord::Base belongs_to :blog belongs_to :user end
  • 28. Polymorphic Associations Easiest to illustrate by example © Vita Rara, Inc. class Person < ActiveRecord::Base has_one :address, :as => :addressable end class Company < ActiveRecord::Base has_one :address, :as => :addressable end class Address < ActiveRecord::Base belongs_to :addressable, :polymorphic => true end create_table :addresses do |t| # ... t.integer :addressable_id t.string :addressable_type end
  • 30. Validation Validations are rules in your model objects to help protect the integrity of your data Validation is invoked by the #save method. Save returns true if validations pass and false otherwise. If you invoke #save! then a RecordInvalid exception is raised if the object is not valid. Use save(false) if you need to turn off validation © Vita Rara, Inc.
  • 31. Validation Callbacks #validate Called before a model is written to the database, either on initial save, or on updates. #validate_on_create Called before a model is inserted into the database. #validate_on_update Called before an existing model is updated in the database. © Vita Rara, Inc.
  • 32. Validation Callbacks (cont) © Vita Rara, Inc. class Person < ActiveRecord::Base def validate puts “validate invoked” end def validate_on_create puts “validate_on_create invoked” end def validate_on_update puts “validate_on_update invoked” end end peter = Person.create(:name => “Peter”) # => peter.validate and peter.validate_on_create invoked peter.last_name = “Forsberg” peter.save # => peter.validate_on_update invoked
  • 33. Declarative Validations © Vita Rara, Inc. Rails contains a large number of declarative validations that are applied to classes by convention. Declarative validations free developers from the drudgery of most model validation.
  • 34. validates_presence_of Used to denote required attributes. © Vita Rara, Inc. class Person < ActiveRecord::Base validates_presence_of :first_name validates_presence_of :last_name end p = Person. new p.valid? #=> false p.first_name = 'Mark' p.last_name = 'Menard' p.valid? #=> true
  • 35. validates_uniqueness_of Ensures that the value of an attribute is unique in the database. Can be constrained to work subsets of the data. © Vita Rara, Inc. class User < ActiveRecord::Base belongs_to :account validates_uniqueness_of :login, :scope => [ :account ] end account = Account.find(1) user_1 = account.users.create(:login => 'mark' ) user_2 = account.users.create!(:login => 'mark' ) #=> Throws InvalidRecord exceptoion
  • 36. validates_numericality_of Ensures that an attribute is a number. Can be constrained to integral values. © Vita Rara, Inc. class User < ActiveRecord::Base validates_numericality_of :number, :integer_only => true end User.create!(:number => 'some number' ) #=> Throws Invalid
  • 37. validates_length_of Ensures an attribute is the proper length © Vita Rara, Inc. class User < ActiveRecord::Base validates_length_of :login, :within => 3 .. 20 validates_length_of :password, :is => 8 validates_length_of :name, :minimum => 3 end
  • 38. validates_format_of Ensures the format of an attribute matches regular expression. Can be used to validate email addresses. © Vita Rara, Inc. class User < ActiveRecord::Base validates_format_of :email, :with => /^[\w\d]+$/ end
  • 39. validates_inclusion_of & validates_exclusion_of Ensures that a value is or is not in a collection of options. © Vita Rara, Inc. class User < ActiveRecord::Base validates_inclusion_of :gender, :in => %w( male female ) , :message => &quot;Oh really....&quot; validates_exclusion_of :login, :in => %w( root admin super ) , :message => &quot;Tisk tisk...&quot; end
  • 40. validates_associated Ensures that an associated model is valid prior to saving. © Vita Rara, Inc. class User < ActiveRecord::Base belongs_to :account validates_associated :account, :on => :create end class Account < ActiveRecord::Base validates_presence_of :name end user = User. new (:login => 'mark' , :name => 'Mark Menard' ) user.account = Account. new # invalid missing name user.save! #=> Throws RecordInvalid exception.
  • 41. Other Declarative Validations validates_acceptance_of validates_confirmation_of validates_each validates_size_of © Vita Rara, Inc. You can also create your own declarative validations that match your problem domain.
  • 42. Using Validation Callbacks Sometimes validation is more complex than the declarative validations can handle. Validation may relate to the semantics of your problem domain. Validation may relate to more than one attribute. © Vita Rara, Inc. class Account validate :does_domain_exist private def does_domain_exist Resolv.getaddress(self.domain_name) rescue errors.add(:domain_name, 'Domain name does not exist.' ) end end
  • 43. Using Validation Callbacks Class methods for defining validation call backs: validate :method_name validate_on_update :method_name validate_on_create :method_name Instance methods for defining validations: validate validate_on_update validate_on_create © Vita Rara, Inc.
  • 45. New Model Callbacks ActiveRecord calls these methods prior to saving a new record: before_validation before_validation_on_create validation is performed after_validation after_validation_on_create before_save before_create ActiveRecord saves the record after_create after_save © Vita Rara, Inc.
  • 46. Existing Model Callbacks ActiveRecord calls these methods prior to saving an existing record before_validation ActiveRecord performs validation after_validation before_save before_update ActiveRecord saves the record after_update after_save © Vita Rara, Inc.
  • 47. Destroy Model Callbacks ActiveRecord calls these methods when destroying a model: before_destroy ActiveRecord performs the DELETE after_destroy © Vita Rara, Inc.
  • 48. Callback Use Cases Cleaning up attributes prior to saving Starting followup processes Sending notifications Geocoding Paranoia: Don’t delete anything just mark it deleted. Clean up associated files, avatars, other assets. © Vita Rara, Inc.
  • 49. Cleaning up Attributes Prior to Saving © Vita Rara, Inc. class CreditCard before_validation :cleanup_number private def cleanup_number self.number = number.gsub( /[^0-9]/ , &quot;&quot; ) true # I like to be explicit end end
  • 51. Observers Observers allow you to create classes that observe changes in your Models. Observers allow you classes to focus on a single responsibility. Observers can hook onto the standard rails life cycle call backs. © Vita Rara, Inc.
  • 52. Creating an Audit Trail with an Observer © Vita Rara, Inc. # in config/environment.rb config.active_record_observers = [ :auditor ] # in auditor.rb class Auditor < ActiveRecord::Observer observe User def after_create (model) log_info( &quot;New #{model.class.name} created.&quot; , model) end def after_update (model) log_info( &quot;Update #{model.class.name}&quot; , model) end def after_destroy (model) log_info( &quot;Destroy #{model.class.name}&quot; , model) end private def log_info (model, info) log.info(info) log.info(model.inspect) end end
  • 54. Ruby and Rails Training One day to three day programs. Introduction to Ruby Advanced Ruby Introduction to Rails Advanced Rails Test Driven Development Behavior Driven Development Test Anything with Cucumber Advanced Domain Modeling with ActiveRecord Domain Driven Development with Rails © Vita Rara, Inc.
  • 55. Ruby on Rails Consulting Full Life Cycle Project Development Inception Implementation Deployment Long Term Support Ruby on Rails Mentoring Get your team up to speed using Rails © Vita Rara, Inc.
  • 56. Contact Information Mark Menard [email_address] http://www.vitarara.net / 518 369 7356 © Vita Rara, Inc.

Editor's Notes

  • #4: This definition supposes a relational data store. The active record pattern would not apply to document oriented systems such as CouchDB, Mongo, and other No-SQL databases, as they tend to store aggregates.
  • #15: I rarely use these options. :select can lead to confusion if you select columns from more than one table because the returned objects will be read-only. I have yet to find a common use case for :group
  • #16: Many times complex views will want to be backed by a custom finder to avoid N+1 issues. I usually place these in a finder module mixed into my model class to keep the model class clean.
  • #19: This is where we begin joining models to other models to reflect the domain space.
  • #26: I very rarely use this type of association. I find that my join models eventually begin to a
  • #49: To halt the chain return false. To continue return true.