Supporting the etag and last modified timestamp in HTTP headers means that Rails can now send back an empty response if it gets a request for a resource that hasn’t been modified lately. This allows you to check whether a response needs to be sent at all.
The work done to make Rails thread-safe is rolling out in Rails 2.2. Depending on your web server infrastructure, this means you can handle more requests with fewer copies of Rails in memory, leading to better server performance and higher utilization of multiple cores.
To enable multithreaded dispatching in production mode of your application, add the following line in your config/environments/production.rb:
5.2. Connection Pooling
Connection pooling lets Rails distribute database requests across a pool of database connections that will grow to a maximum size (by default 5, but you can add a pool key to your database.yml to adjust this). This helps remove bottlenecks in applications that support many concurrent users. There’s also a wait_timeout that defaults to 5 seconds before giving up. ActiveRecord::Base.connection_pool gives you direct access to the pool if you need it.
5.3. Hashes for Join Table Conditions
You can now specify conditions on join tables using a hash. This is a big help if you need to query across complex joins.
5.4.1. find_last_by_<attribute>
The find_last_by_<attribute> method is equivalent to Model.last(:conditions => {:attribute => value})
The new bang! version of find_by_<attribute>! is equivalent to Model.first(:conditions => {:attribute => value}) || raise ActiveRecord::RecordNotFound Instead of returning nil if it can’t find a matching record, this method will raise an exception if it cannot find a match.
6.1. Shallow Route Nesting
Shallow route nesting provides a solution to the well-known difficulty of using deeply-nested resources. With shallow nesting, you need only supply enough information to uniquely identify the resource that you want to work with.
6.2. Method Arrays for Member or Collection Routes
You can now supply an array of methods for new member or collection routes. This removes the annoyance of having to define a route as accepting any verb as soon as you need it to handle more than one. With Rails 2.2, this is a legitimate route declaration:
6.3. Resources With Specific Actions
By default, when you use map.resources to create a route, Rails generates routes for seven default actions (index, show, create, new, edit, update, and destroy). But each of these routes takes up memory in your application, and causes Rails to generate additional routing logic. Now you can use the :only and :except options to fine-tune the routes that Rails will generate for resources. You can supply a single action, an array of actions, or the special :all or :none options. These options are inherited by nested resources.
9.1. Memoization
Memoization is a pattern of initializing a method once and then stashing its value away for repeat use. You’ve probably used this pattern in your own applications:
Memoization lets you handle this task in a declarative fashion:
9.2. each_with_object
The each_with_object method provides an alternative to inject, using a method backported from Ruby 1.9. It iterates over a collection, passing the current element and the memo into the block.
9.3. Delegates With Prefixes
If you delegate behavior from one class to another, you can now specify a prefix that will be used to identify the delegated methods. For example:
This will produce delegated methods vendor#account_email and vendor#account_password. You can also specify a custom prefix:
Action Mailer Basics
+This guide should provide you with all you need to get started in sending emails from your application, and will also cover how to test your mailers.
1. What is Action Mailer?
+Action Mailer allows you to send email from your application using a mailer model and views. +Yes, that is correct, in Rails, emails are used by creating Models that inherit from ActionMailer::Base. They live alongside other models in /app/models BUT they have views just like controllers that appear alongside other views in app/views.
2. Quick walkthrough to creating a Mailer
+Let’s say you want to send a welcome email to a user after they signup. Here is how you would go about this:
2.1. 1. Create the mailer:
+./script/generate mailer UserMailer +exists app/models/ +create app/views/user_mailer +exists test/unit/ +create test/fixtures/user_mailer +create app/models/user_mailer.rb +create test/unit/user_mailer_test.rb
So we got the model, the fixtures, and the tests all created for us
2.2. 2. Edit the model:
+class UserMailer < ActionMailer::Base + +end
Lets add a method called welcome_email, that will send an email to the user’s registered email address:
class UserMailer < ActionMailer::Base + + def welcome_email(user) + recipients user.email + from "My Awesome Site Notifications<notifications@example.com>" + subject "Welcome to My Awesome Site" + sent_on Time.now + body {:user => user, :url => "http://example.com/login"} + content_type "text/html" + end + +end
So what do we have here? +recipients: who the recipients are, put in an array for multiple, ie, @recipients = ["user1@example.com", "user2@example.com"] +from: Who the email will appear to come from in the recipients' mailbox +subject: The subject of the email +sent_on: Timestamp for the email +content_type: The content type, by default is text/plain
How about @body[:user]? Well anything you put in the @body hash will appear in the mailer view (more about mailer views below) as an instance variable ready for you to use, ie, in our example the mailer view will have a @user instance variable available for its consumption.
2.3. 3. Create the mailer view
+The file can look like:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html> + <head> + <meta content='text/html; charset=iso-8859-1' http-equiv='Content-Type' /> + </head> + <body> + <h1>Welcome to example.com, <%= @user.first_name %></h1> + + <p> + You have successfully signed up to example.com, and your username is: <%= @user.login %>.<br/> + To login to the site, just follow this link: <%= @url %>. + </p> + <p>Thanks for joining and have a great day!</p> + </body> +</html>
2.4. 4. Wire it up so that the system sends the email when a user signs up
+There are 3 was to achieve this. One is to send the email from the controller that sends the email, another is to put it in a before_create block in the user model, and the last one is to use an observer on the user model. Whether you use the second or third methods is up to you, but staying away from the first is recommended. Not because it’s wrong, but because it keeps your controller clean, and keeps all logic related to the user model within the user model. This way, whichever way a user is created (from a web form, or from an API call, for example), we are guaranteed that the email will be sent.
# Code that already exists + +Rails::Initializer.run do |config| + + # Code that already exists + + config.active_record.observers = :user_observer + +end
# Code that already exists + +Rails::Initializer.run do |config| + + # Code that already exists + + config.load_paths += %W(#{RAILS_ROOT}/app/observers) + + config.active_record.observers = :user_observer + +end
ALMOST THERE :) Now all we need is that danged observer, and we’re done:
class UserObserver < ActiveRecord::Observer + def after_create(user) + UserMailer.deliver_welcome_email(user) + end +end
Notice how we call deliver_welcome_email? Where is that method? Well if you remember, we created a method called welcome_email in UserMailer, right? Well, as part of the "magic" of rails, we deliver the email identified by welcome_email by calling deliver_welcome_email.
That’s it! Now whenever your users signup, they will be greeted with a nice welcome email. Next up, we’ll talk about how to test a mailer model.
3. Mailer Testing
+A controller is a Ruby class which inherits from ApplicationController and has methods just like any other class. When your application receives a request, the routing will determine which controller and action to run, then Rails creates an instance of that controller and runs the public method with the same name as the action.
There’s no rule saying a method on a controller has to be an action; they may well be used for other purposes such as filters, which will be covered later in this guide.
As an example, if a user goes to /clients/new in your application to add a new client, Rails will create an instance of ClientsController and run the new method. Note that the empty method from the example above could work just fine because Rails will by default render the new.html.erb view unless the action says otherwise. The new method could make available to the view a @client instance variable by creating a new Client:
You will probably want to access data sent in by the user or other parameters in your controller actions. There are two kinds of parameters possible in a web application. The first are parameters that are sent as part of the URL, called query string parameters. The query string is everything after "?" in the URL. The second type of parameter is usually referred to as POST data. This information usually comes from a HTML form which has been filled in by the user. It’s called POST data because it can only be sent as part of an HTTP POST request. Rails does not make any distinction between query string parameters and POST parameters, and both are available in the params hash in your controller:
3.2. Routing Parameters
The params hash will always contain the :controller and :action keys, but you should use the methods controller_name and action_name instead to access these values. Any other parameters defined by the routing, such as :id will also be available. As an example, consider a listing of clients where the list can show either active or inactive clients. We can add a route which captures the :status parameter in a "pretty" URL:
Read more about session storage in the Security Guide.
If you need a different session storage mechanism, you can change it in the config/environment.rb file:
Session values are stored using key/value pairs like a hash:
To store something in the session, just assign it to the key like a hash:
To remove something from the session, assign that key to be nil:
4.2. The flash
The flash is a special part of the session which is cleared with each request. This means that values stored there will only be available in the next request, which is useful for storing error messages etc. It is accessed in much the same way as the session, like a hash. Let’s use the act of logging out as an example. The controller can send a message which will be displayed to the user on the next request:
This way, if an action sets an error or a notice message, the layout will display it automatically.
If you want a flash value to be carried over to another request, use the keep method:
4.2.1. flash.now
By default, adding values to the flash will make them available to the next request, but sometimes you may want to access those values in the same request. For example, if the create action fails to save a resource and you render the new template directly, that’s not going to result in a new request, but you may still want to display a message using the flash. To do this, you can use flash.now in the same way you use the normal flash:
Your application can store small amounts of data on the client - called cookies - that will be persisted across requests and even sessions. Rails provides easy access to cookies via the cookies method, which - much like the session - works like a hash:
Filters are methods that are run before, after or "around" a controller action. For example, one filter might check to see if the logged in user has the right credentials to access that particular controller or action. Filters are inherited, so if you set a filter on ApplicationController, it will be run on every controller in your application. A common, simple filter is one which requires that a user is logged in for an action to be run. You can define the filter method this way:
The method simply stores an error message in the flash and redirects to the login form if the user is not logged in. If a before filter (a filter which is run before the action) renders or redirects, the action will not run. If there are additional filters scheduled to run after the rendering or redirecting filter, they are also cancelled. To use this filter in a controller, use the before_filter method:
In this example, the filter is added to ApplicationController and thus all controllers in the application. This will make everything in the application require the user to be logged in in order to use it. For obvious reasons (the user wouldn’t be able to log in in the first place!), not all controllers or actions should require this. You can prevent this filter from running before particular actions with skip_before_filter:
6.1. After Filters and Around Filters
In addition to the before filters, you can run filters after an action has run or both before and after. The after filter is similar to the before filter, but because the action has already been run it has access to the response data that’s about to be sent to the client. Obviously, after filters can not stop the action from running. Around filters are responsible for running the action, but they can choose not to, which is the around filter’s way of stopping it.
While the most common way to use filters is by creating private methods and using *_filter to add them, there are two other ways to do the same thing.
The first is to use a block directly with the *_filter methods. The block receives the controller as an argument, and the require_login filter from above could be rewritten to use a block:
Note that the filter in this case uses send because the logged_in? method is private and the filter is not run in the scope of the controller. This is not the recommended way to implement this particular filter, but in more simple cases it might be useful.
The second way is to use a class (actually, any object that responds to the right methods will do) to handle the filtering. This is useful in cases that are more complex than can not be implemented in a readable and reusable way using the two other methods. As an example, you could rewrite the login filter again to use a class:
Verifications make sure certain criteria are met in order for a controller or action to run. They can specify that a certain key (or several keys in the form of an array) is present in the params, session or flash hashes or that a certain HTTP method was used or that the request was made using XMLHTTPRequest (Ajax). The default action taken when these criteria are not met is to render a 400 Bad Request response, but you can customize this by specifying a redirect URL or rendering something else and you can also add flash messages and HTTP headers to the response. It is described in the API documentation as "essentially a special kind of before_filter".
Here’s an example of using verification to make sure the user supplies a username and a password in order to log in:
Now the create action won’t run unless the "username" and "password" parameters are present, and if they’re not, an error message will be added to the flash and the new action will be rendered. But there’s something rather important missing from the verification above: It will be used for every action in LoginsController, which is not what we want. You can limit which actions it will be used for with the :only and :except options just like a filter:
Cross-site request forgery is a type of attack in which a site tricks a user into making requests on another site, possibly adding, modifying or deleting data on that site without the user’s knowledge or permission. The first step to avoid this is to make sure all "destructive" actions (create, update and destroy) can only be accessed with non-GET requests. If you’re following RESTful conventions you’re already doing this. However, a malicious site can still send a non-GET request to your site quite easily, and that’s where the request forgery protection comes in. As the name says, it protects from forged requests. The way this is done is to add a non-guessable token which is only known to your server to each request. This way, if a request comes in without the proper token, it will be denied access.
If you generate a form like this:
You will see how the token gets added as a hidden field:
9.2.1. Setting Custom Headers
If you want to set custom headers for a response then response.headers is the place to do it. The headers attribute is a hash which maps header names to their values, and Rails will set some of them - like "Content-Type" - automatically. If you want to add or change a header, just assign it to headers with the name and value:
Rails comes with built-in HTTP Basic authentication. This is an authentication scheme that is supported by the majority of browsers and other HTTP clients. As an example, consider an administration section which will only be available by entering a username and a password into the browser’s HTTP Basic dialog window. Using the built-in authentication is quite easy and only requires you to use one method, authenticate_or_request_with_http_basic.
Sometimes you may want to send a file to the user instead of rendering an HTML page. All controllers in Rails have the send_data and the send_file methods, that will both stream data to the client. send_file is a convenience method which lets you provide the name of a file on the disk and it will stream the contents of that file for you.
To stream data to the client, use send_data:
11.1. Sending Files
If you want to send a file that already exists on disk, use the send_file method. This is usually not recommended, but can be useful if you want to perform some authentication before letting the user download the file.
11.2. RESTful Downloads
While send_data works just fine, if you are creating a RESTful application having separate actions for file downloads is usually not necessary. In REST terminology, the PDF file from the example above can be considered just another representation of the client resource. Rails provides an easy and quite sleek way of doing "RESTful downloads". Here’s how you can rewrite the example so that the PDF download is a part of the show action, without any streaming:
In order for this example to work, you have to add the PDF MIME type to Rails. This can be done by adding the following line to the file config/initializers/mime_types.rb:
Rails keeps a log file for each environment (development, test and production) in the log folder. These are extremely useful when debugging what’s actually going on in your application, but in a live application you may not want every bit of information to be stored in the log file. The filter_parameter_logging method can be used to filter out sensitive information from the log. It works by replacing certain values in the params hash with "[FILTERED]" as they are written to the log. As an example, let’s see how to filter all parameters with keys that include "password":
If you want to do something a bit more elaborate when catching errors, you can use rescue_from, which handles exceptions of a certain type (or multiple types) in an entire controller and its subclasses. When an exception occurs which is caught by a rescue_from directive, the exception object is passed to the handler. The handler can be a method or a Proc object passed to the :with option. You can also use a block directly instead of an explicit Proc object.
Here’s how you can use rescue_from to intercept all ActiveRecord::RecordNotFound errors and do something with them.
Of course, this example is anything but elaborate and doesn’t improve on the default exception handling at all, but once you can catch all those exceptions you’re free to do whatever you want with them. For example, you could create custom exception classes that will be thrown when a user doesn’t have access to a certain section of your application:
If you’re used to using raw SQL to find database records then, generally, you will find that there are better ways to carry out the same operations in Rails. Active Record insulates you from the need to use SQL in most cases.
Code examples throughout this guide will refer to one or more of the following models:
class MailingAddress < Address end
To retrieve objects from the database, Active Record provides a primary method called find. This method allows you to pass arguments into it to perform certain queries on your database without the need of SQL. If you wanted to find the record with the id of 1, you could type Client.find(1) which would execute this query on your database:
If you wanted to find clients with id 1 or 2, you call Client.find([1,2]) or Client.find(1,2) and then this will be executed as:
If you were reading your log file (the default is log/development.log) you may see something like this:
If you were reading your log file (the default is log/development.log) you may see something like this:
Now what if that number could vary, say as a argument from somewhere, or perhaps from the user’s level status somewhere? The find then becomes something like Client.first(:conditions => ["orders_count = ?", params[:orders]]). Active Record will go through the first element in the conditions value and any additional elements will replace the question marks (?) in the first element. If you want to specify two conditions, you can do it like Client.first(:conditions => ["orders_count = ? AND locked = ?", params[:orders], false]). In this example, the first question mark will be replaced with the value in params[:orders] and the second will be replaced with the SQL representation of false, which depends on the adapter.
The reason for doing code like:
Client.first(:conditions => ["orders_count = ?", params[:orders]])
instead of:
If you’re looking for a range inside of a table (for example, users created in a certain timeframe) you can use the conditions option coupled with the IN sql statement for this. If you had two dates coming in from a controller you could do something like this to look for a range:
This would generate the proper query which is great for small ranges but not so good for larger ranges. For example if you pass in a range of date objects spanning a year that’s 365 (or possibly 366, depending on the year) strings it will attempt to match your field against.
Things can get really messy if you pass in Time objects as it will attempt to compare your field to every second in that range:
Client.all(:conditions => ["created_at IN (?)", (params[:start_date].to_date.to_time)..(params[:end_date].to_date.to_time)])
Where query is the actual query used to get that error.
In this example it would be better to use greater-than and less-than operators in SQL, like so:
You can also use the greater-than-or-equal-to and less-than-or-equal-to like this:
2.3. Placeholder Conditions
Similar to the array style of params you can also specify keys in your conditions:
2.4. Hash Conditions
Rails also allows you to pass in a hash conditions which can increase the readability of your conditions syntax. With hash conditions, you pass in a hash with keys of the fields you want conditionalised and the values of how you want to conditionalise them:
Client.all(:conditions => { :locked => true })
The field name does not have to be a symbol it can also be a string:
Client.all(:conditions => { 'locked' => true })
The good thing about this is that we can pass in a range for our fields without it generating a large query as shown in the preamble of this section.
Client.all(:conditions => { :created_at => (Time.now.midnight - 1.day)..Time.now.midnight})
This will find all clients created yesterday by using a BETWEEN sql statement:
This demonstrates a shorter syntax for the examples in Array Conditions
You can also join in tables and specify their columns in the hash:
Client.all(:include => "orders", :conditions => { 'orders.created_at' => (Time.now.midnight - 1.day)..Time.now.midnight })
An alternative and cleaner syntax to this is:
This will find all clients who have orders that were created yesterday, again using a BETWEEN expression.
If you want to find records using the IN expression you can pass an array to the conditions hash:
Client.all(:include => "orders", :conditions => { :orders_count => [1,3,5] }
This code will generate SQL like this:
If you want to limit the amount of records to a certain subset of all the records retrieved you usually use limit for this, sometimes coupled with offset. Limit is the maximum number of records that will be retrieved from a query, and offset is the number of records it will start reading from from the first record of the set. Take this code for example:
Client.all(:limit => 5)
This code will return a maximum of 5 clients and because it specifies no offset it will return the first 5 clients in the table. The SQL it executes will look like this:
SELECT * FROM clients LIMIT 5
Client.all(:limit => 5, :offset => 5)
This code will return a maximum of 5 clients and because it specifies an offset this time, it will return these records starting from the 5th client in the clients table. The SQL looks like:
The group option for find is useful, for example, if you want to find a collection of the dates orders were created on. You could use the option in this context:
And this will give you a single Order object for each date where there are orders in the database.
The SQL that would be executed would be something like this:
The :having option allows you to specify SQL and acts as a kind of a filter on the group option. :having can only be specified when :group is specified.
An example of using it would be:
readonly is a find option that you can set in order to make that instance of the record read-only. Any attempt to alter or destroy the record will not succeed, raising an ActiveRecord::ReadOnlyRecord exception. To set this option, specify it like this:
Client.first(:readonly => true)
If you assign this record to a variable client, calling the following code will raise an ActiveRecord::ReadOnlyRecord exception:
If you’re wanting to stop race conditions for a specific record (for example, you’re incrementing a single field for a record, potentially from multiple simultaneous connections) you can use the lock option to ensure that the record is updated correctly. For safety, you should use this inside a transaction.
You can also pass SQL to this option to allow different types of locks. For example, MySQL has an expression called LOCK IN SHARE MODE where you can lock a record but still allow other queries to read it. To specify this expression just pass it in as the lock option:
Eager loading is loading associated records along with any number of records in as few queries as possible. For example, if you wanted to load all the addresses associated with all the clients in a single query you could use Client.all(:include => :address). If you wanted to include both the address and mailing address for the client you would use Client.find(:all, :include => [:address, :mailing_address]). Include will first find the client records and then load the associated address records. Running script/server in one window, and executing the code through script/console in another window, the output should look similar to this:
If you wanted to get all the addresses for a client in the same query you would do Client.all(:joins => :address). If you wanted to find the address and mailing address for that client you would do Client.all(:joins => [:address, :mailing_address]). This is more efficient because it does all the SQL in one query, as shown by this example:
This query is more efficent, but there’s a gotcha: if you have a client who does not have an address or a mailing address they will not be returned in this query at all. If you have any association as an optional association, you may want to use include rather than joins. Alternatively, you can use a SQL join clause to specify exactly the join you need (Rails always assumes an inner join):
When using eager loading you can specify conditions for the columns of the tables inside the eager loading to get back a smaller subset. If, for example, you want to find a client and all their orders within the last two weeks you could use eager loading with conditions for this:
If you want to find both by name and locked, you can chain these finders together by simply typing and between the fields for example Client.find_by_name_and_locked("Ryan", true).
There’s another set of dynamic finders that let you find or create/initialize objects if they aren’t found. These work in a similar fashion to the other finders and can be used like find_or_create_by_name(params[:name]). Using this will firstly perform a find and then create if the find returns nil. The SQL looks like this for Client.find_or_create_by_name("Ryan"):
find_or_create's sibling, find_or_initialize, will find an object and if it does not exist will act similar to calling new with the arguments you passed in. For example:
If you’d like to use your own SQL to find records in a table you can use find_by_sql. The find_by_sql method will return an array of objects even the underlying query returns just a single record. For example you could run this query:
find_by_sql has a close relative called connection#select_all. select_all will retrieve objects from the database using custom SQL just like find_by_sql but will not instantiate them. Instead, you will get an array of hashes where each hash indicates a record.
16.1. Simple Named Scopes
Suppose we want to find all clients who are male. You could use this code:
Then you could call Client.males.all to get all the clients who are male. Please note that if you do not specify the all on the end you will get a Scope object back, not a set of records which you do get back if you put the all on the end.
If you wanted to find all the clients who are active, you could use this:
16.2. Combining Named Scopes
If you wanted to find all the clients who are active and male you can stack the named scopes like this:
Client.males.active.all
If you would then like to do a all on that scope, you can. Just like an association, named scopes allow you to call all on them:
16.3. Runtime Evaluation of Named Scope Conditions
Consider the following code:
This looks like a standard named scope that defines a method called recent which gathers all records created any time between now and 2 weeks ago. That’s correct for the first time the model is loaded but for any time after that, 2.weeks.ago is set to that same value, so you will consistently get records from a certain date until your model is reloaded by something like your application restarting. The way to fix this is to put the code in a lambda block:
16.4. Named Scopes with Multiple Models
In a named scope you can use :include and :joins options just like in find.
16.5. Arguments to Named Scopes
If you want to pass to a named scope a required arugment, just specify it as a block argument like this:
This will work if you call Client.recent(2.weeks.ago).all but not if you call Client.recent. If you want to add an optional argument for this, you have to use prefix the arugment with an *.
16.6. Anonymous Scopes
All Active Record models come with a named scope named scoped, which allows you to create anonymous scopes. For example:
Anonymous scopes are most useful to create scopes "on the fly":
If you simply want to check for the existence of the object there’s a method called exists?. This method will query the database using the same query as find, but instead of returning an object or collection of objects it will return either true or false+.
Client.exists?(1)
The exists? method also takes multiple ids, but the catch is that it will return true if any one of those records exists.
Further more, exists takes a conditions option much like find:
This section uses count as an example method in this preamble, but the options described apply to all sub-sections.
count takes conditions much in the same way exists? does:
Client.count(:conditions => "first_name = 'Ryan'")
Which will execute:
SELECT count(*) AS count_all FROM clients WHERE (first_name = 'Ryan')
You can also use :include or :joins for this to do something a little more complex:
Client.count(:conditions => "clients.first_name = 'Ryan' AND orders.status = 'received'", :include => "orders")
Which will execute:
18.2. Average
If you want to see the average of a certain number in one of your tables you can call the average method on the class that relates to the table. This method call will look something like this:
18.3. Minimum
If you want to find the minimum value of a field in your table you can call the minimum method on the class that relates to the table. This method call will look something like this:
18.4. Maximum
If you want to find the maximum value of a field in your table you can call the maximum method on the class that relates to the table. This method call will look something like this:
18.5. Sum
If you want to find the sum of a field for all records in your table you can call the sum method on the class that relates to the table. This method call will look something like this:
1.2. When Does Validation Happen?
There are two kinds of Active Record objects: those that correspond to a row inside your database and those that do not. When you create a fresh object, using the new method, that object does not belong to the database yet. Once you call save upon that object it will be saved into the appropriate database table. Active Record uses the new_record? instance method to determine whether an object is already in the database or not. Consider the following simple Active Record class:
2.1. The validates_acceptance_of helper
Validates that a checkbox on the user interface was checked when a form was submitted. This is normally used when the user needs to agree to your application’s terms of service, confirm reading some text, or any similar concept. This validation is very specific to web applications and actually this acceptance does not need to be recorded anywhere in your database (if you don’t have a field for it, the helper will just create a virtual attribute).
The default error message for validates_acceptance_of is "must be accepted"
validates_acceptance_of can receive an :accept option, which determines the value that will be considered acceptance. It defaults to "1", but you can change this.
2.2. The validates_associated helper
You should use this helper when your model has associations with other models and they also need to be validated. When you try to save your object, valid? will be called upon each one of the associated objects.
2.3. The validates_confirmation_of helper
You should use this helper when you have two text fields that should receive exactly the same content. For example, you may want to confirm an email address or a password. This validation creates a virtual attribute, using the name of the field that has to be confirmed with _confirmation appended.
In your view template you could use something like
2.4. The validates_exclusion_of helper
This helper validates that the attributes' values are not included in a given set. In fact, this set can be any enumerable object.
2.5. The validates_format_of helper
This helper validates the attributes' values by testing whether they match a given pattern. This pattern must be specified using a Ruby regular expression, which is specified using the :with option.
2.6. The validates_inclusion_of helper
This helper validates that the attributes' values are included in a given set. In fact, this set can be any enumerable object.
2.7. The validates_length_of helper
This helper validates the length of your attribute’s value. It includes a variety of different options, so you can specify length constraints in different ways:
The default error messages depend on the type of length validation being performed. You can personalize these messages, using the :wrong_length, :too_long and :too_short options and the %d format mask as a placeholder for the number corresponding to the length constraint being used. You can still use the :message option to specify an error message.
This helper validates that your attributes have only numeric values. By default, it will match an optional sign followed by a integral or floating point number. Using the :integer_only option set to true, you can specify that only integral numbers are allowed.
If you set :integer_only to true, then it will use the $$/\A[\-]?\d+\Z/ regular expression to validate the attribute’s value. Otherwise, it will try to convert the value to a number using +Kernel.Float.
2.9. The validates_presence_of helper
This helper validates that the specified attributes are not empty. It uses the blank? method to check if the value is either nil or an empty string (if the string has only spaces, it will still be considered empty).
2.10. The validates_uniqueness_of helper
This helper validates that the attribute’s value is unique right before the object gets saved. It does not create a uniqueness constraint directly into your database, so it may happen that two different database connections create two records with the same value for a column that you intend to be unique. To avoid that, you must create an unique index in your database.
The validation happens by performing a SQL query into the model’s table, searching for a record where the attribute that must be validated is equal to the value in the object being validated.
There is a :scope option that you can use to specify other attributes that are used to limit the uniqueness check:
There is also a :case_sensitive option that you can use to define whether the uniqueness constraint will be case sensitive or not. This option defaults to true.
2.11. The validates_each helper
This helper validates attributes against a block. It doesn’t have a predefined validation function. You should create one using a block, and every attribute passed to validates_each will be tested against it. In the following example, we don’t want names and surnames to begin with lower case.
3.1. The :allow_nil option
The :allow_nil option skips the validation when the value being validated is nil. You may be asking yourself if it makes any sense to use :allow_nil and validates_presence_of together. Well, it does. Remember, the validation will be skipped only for nil attributes, but empty strings are not considered nil.
3.2. The :allow_blank option
The :allow_blank: option is similar to the +:allow_nil option. This option will let validation pass if the attribute’s value is nil or an empty string, i.e., any value that returns true for blank?.
3.4. The :on option
The :on option lets you specify when the validation should happen. The default behavior for all the built-in validation helpers is to be ran on save (both when you’re creating a new record and when you’re updating it). If you want to change it, you can use :on => :create to run the validation only when a new record is created or :on => :update to run the validation only when a record is updated.
4.1. Using a symbol with the :if and :unless options
You can associate the :if and :unless options with a symbol corresponding to the name of a method that will get called right before validation happens. This is the most commonly used option.
4.2. Using a string with the :if and :unless options
You can also use a string that will be evaluated using :eval and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition.
4.3. Using a Proc object with the :if and :unless options
Finally, it’s possible to associate :if and :unless with a Ruby Proc object which will be called. Using a Proc object can give you the hability to write a condition that will be executed only when the validation happens and not when your code is loaded by the Ruby interpreter. This option is best suited when writing short validation methods, usually one-liners.
When the built-in validation helpers are not enough for your needs, you can write your own validation methods. You can do that by implementing methods that verify the state of your models and add messages to their errors collection when they are invalid. You must then register those methods by using one or more of the validate, validate_on_create or validate_on_update class methods, passing in the symbols for the validation methods' names. You can pass more than one symbol for each class method and the respective validations will be ran in the same order as they were registered.
You can even create your own validation helpers and reuse them in several different models. Here is an example where we create a custom validation helper to validate the format of fields that represent email addresses:
The recipe is simple: just create a new validation method inside the ActiveRecord::Validations::ClassMethods module. You can put this code in a file inside your application’s lib folder, and then requiring it from your environment.rb or any other file inside config/initializers. You can use this helper like this:
Rails provides built-in helpers to display the error messages of your models in your view templates. When creating a form with the form_for helper, you can use the error_messages method on the form builder to render all failed validation messages for the current model instance.
7.1. Changing the way form fields with errors are displayed
By default, form fields with errors are displayed enclosed by a div element with the fieldWithErrors CSS class. However, we can write some Ruby code to override the way Rails treats those fields by default. Here is a simple example where we change the Rails behaviour to always display the error messages in front of each of the form fields with errors. The error messages will be enclosed by a span element with a validation-error CSS class. There will be no div element enclosing the input element, so we get rid of that red border around the text field. You can use the validation-error CSS class to style it anyway you want.
8.1. Callbacks registration
In order to use the available callbacks, you need to registrate them. You can do that by implementing them as an ordinary methods, and then using a macro-style class method to register then as callbacks.
The macro-style class methods can also receive a block. Rails best practices say that you should only use this style of registration if the code inside your block is so short that it fits in just one line.
9.1. Using a symbol with the :if and :unless options
You can associate the :if and :unless options with a symbol corresponding to the name of a method that will get called right before the callback. If this method returns false the callback won’t be executed. This is the most common option. Using this form of registration it’s also possible to register several different methods that should be called to check the if the callback should be executed.
9.2. Using a string with the :if and :unless options
You can also use a string that will be evaluated using :eval and needs to contain valid Ruby code. You should use this option only when the string represents a really short condition.
9.3. Using a Proc object with the :if and :unless options
Finally, it’s possible to associate :if and :unless with a Ruby Proc object. This option is best suited when writing short validation methods, usually one-liners.
9.4. Multiple Conditions for Callbacks
When writing conditional callbacks, it’s possible to mix both :if and :unless in the same callback declaration.
Sometimes the callback methods that you’ll write will be useful enough to be reused at other models. Active Record makes it possible to create classes that encapsulate the callback methods, so it becomes very easy to reuse them.
Here’s an example where we create a class with a after_destroy callback for a PictureFile model.
When declared inside a class the callback method will receive the model object as a parameter. We can now use it this way:
Note that we needed to instantiate a new PictureFileCallbacks object, since we declared our callback as an instance method. Sometimes it will make more sense to have it as a class method.
If the callback method is declared this way, it won’t be necessary to instantiate a PictureFileCallbacks object.
Observer classes are subclasses of the ActiveRecord::Observer class. When this class is subclassed, Active Record will look at the name of the new class and then strip the Observer part to find the name of the Active Record class to observe.
Consider a Registration model, where we want to send an email every time a new registration is created. Since sending emails is not directly related to our model’s purpose, we could create an Observer to do just that:
Like in callback classes, the observer’s methods receive the observed model as a parameter.
Sometimes using the ModelName + Observer naming convention won’t be the best choice, mainly when you want to use the same observer for more than one model class. It’s possible to explicity specify the models that our observer should observe.
13.1. Registering observers
If you paid attention, you may be wondering where Active Record Observers are referenced in our applications, so they get instantiated and begin to interact with our models. For observers to work we need to register them somewhere. The usual place to do that is in our application’s config/environment.rb file. In this file there is a commented-out line where we can define the observers that our application should load at start-up.
Why do we need associations between models? Because they make common operations simpler and easier in your code. For example, consider a simple Rails application that includes a model for customers and a model for orders. Each customer can have many orders. Without associations, the model declarations would look like this:
Now, suppose we wanted to add a new order for an existing customer. We’d need to do something like this:
@order = Order.create(:order_date => Time.now, :customer_id => @customer.id)
Or consider deleting a customer, and ensuring that all of its orders get deleted as well:
With Active Record associations, we can streamline these - and other - operations by declaratively telling Rails that there is a connection between the two models. Here’s the revised code for setting up customers and orders:
With this change, creating a new order for a particular customer is easier:
@order = @customer.orders.create(:order_date => Time.now)
Deleting a customer and all of its orders is much easier:
2.1. The belongs_to Association
A belongs_to association sets up a one-to-one connection with another model, such that each instance of the declaring model "belongs to" one instance of the other model. For example, if your application includes customers and orders, and each order can be assigned to exactly one customer, you’d declare the order model this way:
2.2. The has_one Association
A has_one association also sets up a one-to-one connection with another model, but with somewhat different semantics (and consequences). This association indicates that each instance of a model contains or possesses one instance of another model. For example, if each supplier in your application has only one account, you’d declare the supplier model like this:
2.3. The has_many Association
A has_many association indicates a one-to-many connection with another model. You’ll often find this association on the "other side" of a belongs_to association. This association indicates that each instance of the model has zero or more instances of another model. For example, in an application containing customers and orders, the customer model could be declared like this:
2.4. The has_many :through Association
A has_many :through association is often used to set up a many-to-many connection with another model. This association indicates that the declaring model can be matched with zero or more instances of another model by proceeding through a third model. For example, consider a medical practice where patients make appointments to see physicians. The relevant association declarations could look like this:
The has_many :through association is also useful for setting up "shortcuts" through nested :has_many associations. For example, if a document has many sections, and a section has many paragraphs, you may sometimes want to get a simple collection of all paragraphs in the document. You could set that up this way:
2.5. The has_one :through Association
A has_one :through association sets up a one-to-one connection with another model. This association indicates that the declaring model can be matched with one instance of another model by proceeding through a third model. For example, if each supplier has one account, and each account is associated with one account history, then the customer model could look like this:
2.6. The has_and_belongs_to_many Association
A has_and_belongs_to_many association creates a direct many-to-many connection with another model, with no intervening model. For example, if your application includes assemblies and parts, with each assembly having many parts and each part appearing in many assemblies, you could declare the models this way:
If you want to set up a 1-1 relationship between two models, you’ll need to add belongs_to to one, and has_one to the other. How do you know which is which?
The distinction is in where you place the foreign key (it goes on the table for the class declaring the belongs_to association), but you should give some thought to the actual meaning of the data as well. The has_one relationship says that one of something is yours - that is, that something points back to you. For example, it makes more sense to say that a supplier owns an account than that an account owns a supplier. This suggests that the correct relationships are like this:
The corresponding migration might look like this:
2.8. Choosing Between has_many :through and has_and_belongs_to_many
Rails offers two different ways to declare a many-to-many relationship between models. The simpler way is to use has_and_belongs_to_many, which allows you to make the association directly:
The second way to declare a many-to-many relationship is to use has_many :through. This makes the association indirectly, through a join model:
2.9. Polymorphic Associations
A slightly more advanced twist on associations is the polymorphic association. With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a picture model that belongs to either an employee model or a product model. Here’s how this could be declared:
You can think of a polymorphic belongs_to declaration as setting up an interface that any other model can use. From an instance of the Employee model, you can retrieve a collection of pictures: @employee.pictures. Similarly, you can retrieve @product.pictures. If you have an instance of the Picture model, you can get to its parent via @picture.imageable. To make this work, you need to declare both a foreign key column and a type column in the model that declares the polymorphic interface:
This migration can be simplified by using the t.references form:
2.10. Self Joins
In designing a data model, you will sometimes find a model that should have a relation to itself. For example, you may want to store all employees in a single database model, but be able to trace relationships such as manager and subordinates. This situation can be modeled with self-joining associations:
