1. ActiveRecord
1.1 New bind-style variable interpolation
There is new bind-style variable interpolation for the condition arrays that uses the adapter’s quote method.
Before:
find_first([ "user_name = '%s' AND password = '%s'", user_name, password ])
find_first([ "firm_id = %s", firm_id ]) # unsafe!
After:
find_first([ "user_name = ? AND password = ?", user_name, password ])
find_first([ "firm_id = ?", firm_id ])
This takes care of wrapping the appropriate quotes around each attribute, in addition to sanitizing the input.
There is also a named bind-style variable interpolation that is used like so:
Person.find_first(
["id = :id and first_name = :first_name",
{ :id => 5, :first_name = "bob' or 1=1" }])
Please update to the new bind style if you use the printf style in your application since its much more secure and can be subject to future optimization when when more database drivers support prepared statements.
If you’d like to do a regular expression search using the ’search term’ notation, such as with mysql, this can be accomplished like so:
find_all([ "username LIKE ?", "%#{username)%" ])
1.2 New macro style class methods for AR model validation
Overview
Validation has taken a big leap forward in simplicity and capability. With easy 1 line methods, you decorate your model with various constraints. Here’s an overview of the macros available:
- validates_confirmation_of
- validates_acceptance_of
- validates_presence_of
- validates_length_of
- validates_uniqueness_of
- validates_format_of
- validates_inclusion_of
validates_presence_of
validates_presence_of is a new macro style method which encapsulates the process of defining a validate method and setting errors.add_on_empty to attributes.
Before:
def validate
errors.add_on_empty %w{first_name last_name username}
end
After:
class User < ActiveRecord::Base
validates_presence_of :first_name, :last_name, :username
end
validates_acceptance_of
validates_acceptance_of encapsulates the pattern of wanting to validate the acceptance of a terms of service box (or some such agreement). Example:
Model:
class Person < ActiveRecord::Base
validates_acceptance_of :terms_of_service
validates_acceptance_of :eula, :message => "must be abided by"
end
View:
<%= check_box "person", "terms_of_service" %>
Note that the terms_of_service attribute is entirely virtual. No database column is needed. This check is performed both on create and update.
The :message option allows you to specify a custom error message (default is: “must be accepted”)
If you want to restrict the validation to just one of the two situations you can include the :on option, as in:
class Person < ActiveRecord::Base
validates_acceptance_of :terms_of_service, :on => :create
end
validates_confirmation_of
validates_confirmation_of encapsulates the pattern of wanting to validate a password or email address field with a confirmation. Example:
Model:
class Person < ActiveRecord::Base
validates_confirmation_of :user_name, :password, :on => :create
validates_confirmation_of :email_address, :message => "should match confirmation"
end
View:
<%= password_field "person", "password" %>
<%= password_field "person", "password_confirmation" %>
The person has to already have a password attribute (a column in the people table), but the password_confirmation is virtual. It exists only as an in-memory variable for validating the password. This check is performed both on create and update.
The :message option allows you to specify a custom error message (default is: “doesn’t match confirmation”)
validates_uniqueness_of
validates_uniqueness_of validates whether the value of the specified attributes are unique across the system. Useful for making sure that only one user can be named “davidhh”.
Model:
class Person < ActiveRecord::Base
validates_uniqueness_of :user_name
end
View:
<%= text_field "person", "user_name" %>
When the record is created, a check is performed to make sure that no record exist in the database with the given value for the specified attribute (that maps to a column). When the record is updated, the same check is made but disregarding the record itself.
The :message option allows you to specify a custom error message (default is: “has already been taken”)
validates_inclusion_of
This validates that an attribute is contained within something. The something can be an Array, a Range, a String, or anything else sporting the include? method.
Model:
class Person < ActiveRecord::Base
validates_inclusion_of :gender, :in => ['m','f']
validates_inclusion_of :temperature, :in => -273..5000
end
validates_length_of
This method specializes in validating string sizes. It supports checking if a string is too small, too big, an exact number, or within a range.
Model:
class Person < ActiveRecord::Base
validates_length_of :first_name, :maximum=>50
validates_length_of :alphabet, :is=>26
validates_length_of :initials, :within=>2..3
end
validates_format_of
This validation performs Regular Expression checks.
class Person < ActiveRecord::Base
validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/
end
1.3 Automatic requiring of dependencies
require 'comment' class Post < ActiveRecord::Base has_many :comments end
You can now leave out the explicit require and just rely on Active Record to follow your association specification and do the require:
class Post < ActiveRecord::Base has_many :comments end
For this to work comments has to be in a file called comments.rb. Note that this does not work for Single table inheritance. You still need to require the parent class. ( please use require_dependency see below…)