Fork me on GitHub

Caching with Rails Part 1: Page Caching

by Phil McClure

alt text

Why do it?

There are three types of caching in Rails. In this tutorial we are going to concentrate on Page Caching. Page caching is the simplest and fastest form of caching in Rails. If you want to reduce the amount of times your Rails app hits the database then why not add some page caching.

When to do it?

Page caching should be done when you want to cache the entire page. So it's best to do this on pages which don't have lots of sections which are updating their content independently of each other (this is better suited to fragment caching, which will be covered in the next article).

How to do it?

First things first! Enable caching for your development environment by editing the environments/development.rb file and changing the perform_caching property to true. Like so:-

config.action_controller.perform_caching = true

Now, edit the controller that relates to the page you want to cache (in my case, the People controller) and add the caches_page method to the top of the class. As you can see from the example below, you need to pass in a symbol, representing the controller action relating to the page you want to cache.

With this in place, you can browse to the page as you normally would. The page will load, as expected, and a database query will be executed to retrieve the relevant data. However, it will also create a cached file called "people.html" in the /public folder. On any subsequent requests, this cached HTML file will be loaded. Happy days!

Expiring the cache

alt text

Caching the page is little use to anyone if you can't expire it. When someone creates and new record, updates a record or destroys a record, you need some mechanism to expire the existing cached file and replace it with new update-to-date cache.

You can expire the cache by calling the expire_page method and passing in a hash with the name of the action. As you would expect, the place to do this is in the methods which update the state of your data i.e. create, update and destroy.

Sweepers

alt text

While the above code works, it isn't very flexible plus it clutters your controller with code which is far from DRY. As always, Rails provides a solution to this and they are called Sweepers. Sweepers use an observer to observe the controller to see when given actions occur. When these actions occur, the sweeper kicks in and expires the cache.

Let's do it! Add the cache_sweeper method to the top of your controller. This tells the sweeper which actions it should observe. In this case, when create, update or destroy is called, the sweeper will jump into action.

Now, create a new sub folder under your "app" folder, called "sweepers". This will hold all your sweeper files. In this folder, create a file called person_sweeper.rb and add the following code.

Finally, since we have created a new folder called "sweepers", we need to tell Rails that it should load file in this folder. To do that, edit your config/environment.rb file and add this code:-

config.load_paths += %W( #{RAILS_ROOT}/app/sweepers )

Now that Rails knows where to locate sweeper files, you can restart your web server and check that everything is working.



Posted on Tue 01 Sep 2009 | Comments

Nested Object Forms in Rails 2.3

by Phil McClure

The Problem

If you work with web applications on a a regular basis, at some point you're going to have to deal with gathering user input for storage in a database or for passing on via email. As you start to model more complex "problem domains, you will find that the forms that you require for gathering related input become much more complex.

For instance, let's take a simplistic example. A "Company" has many "Addresses" as shown by the diagram below.

If you want to create a form that prompts the user for both company and address information, you will need to "nest" the address fields within the company form. So, how do we do it? Well, until recently it was a bit of a hassle, however, "Nested Object Forms" is a new feature in Rails 2.3, which aims to simplify this process. Yah!

So, the Company and Address objects, described above, can be described using the following models:-

How accepts_nested_attributes_for Can Help

alt text

To allow a company form to have nested address fields pre Rails 2.3 you would have to create several attributes that enabled the nested fields to be saved/retrieved from the database. However, in Rails 2.3 we can use the "accepts_nested_attributes_for" method to do a lot of the donkey work for us. To do this, simply change the "Company" model to look like the following:-

Very simple! Essentially, the accepts_nested_attributes_for method integrates the required functionality to allow you to save and retrieve the associated address record(s).

The view will use fields_for, as per usual, to display these related fields:-

One thing to notice in the above example is the setup_company method call. We have yet to set this method up - let's do it now! In your application helper file add the following:-

The method build the required child object in memory, so that the required blank fields appear on the form when creating and editing a company record.

Thats it!



Posted on Tue 01 Sep 2009 | Comments

Single Table Inheritance with Rails

by Phil McClure

What is it?

With single table inheritance you have a base model which inherits from ActiveRecord::Base, then one or more sub-classes, which inherit from the base model.

Single table inheritance is a software pattern described by Martin Fowler. Since (most) databases don't support inheritance, there is an issue when trying to map objects to database tables. This is known as the Object-relational impedance mismatch.

Rails uses the Single Table Inheritance pattern to solve this problem. The basic idea is that another field in the base database table is used to store the type of the object.

Why use it?

If you want to acurately model a domain then inheritance is going to be necessary at some point or another. So single table inheritance gives you this flexibility.

Be Careful!

Just be careful when using single table inheritance. Since all the data from all the sub-types is include in one table, you can end up with a lot of "null"s scattered throughout the table. These ultimately increase the size of the table and you could end up with a scaling problem on your hands.

For instance, say you have an abstract object called "Employee" and several sub-classes called "FullTimeEmployee", "TempEmployee" and "StudentEmployee". This is shown in the class diagram below:

Employee Hierarchy

As you can see, the super-class (Employee) has two instance variables "Name" and "Salary". Further to this, each of the sub-types have an instance variable relating, specifically to them. These instance variables in the sub-classes are what cause the problems. If you have a look at the table below, all will become clear:

Type Name Salary Hours Duration University FullTimeEmployee Jim 10,000 37 null null TempEmployee John 15,000 null 5 null StudentEmployee Joe 20,000 null null Queens University, Belfast

As you can see, each type has nulls in the fields which don't apply to it. This problem is only compounded when extra objects are added. So, as I already mentioned, the scaling problems can be serious, so keep this in mind when modeling your application.

Coding it

Using the "Employee" model above we first need to generate the Employee model:

ruby script/generate model employee name:string salary:string 
hours:string duration:string university:string type:string

Notice we have included a "type" field. This is used to store the type of object that the record applies to. Now migrate this into the database:

rake db:migrate

Now, in the app/models folder create a model file for each sub-class:

full_time_employee.rb

We can now test this out using the console:

>> FullTimeEmployee.create!(:name => "Jim", :salary => "10,000", :hours => "37")
>> TempEmployee.create!(:name => "John", :salary => "15,000", :duration => "5")
>> StudentEmployee.create!(:name => "Joe", :salary => "20,000", 
   :university => "Queens University, Belfast")

Now, print the records, we just created, to screen:

>> y Employee.all

!ruby/object:FullTimeEmployee attributes:

name: Jim
updated_at: 2009-06-12 19:16:42
university:
salary: "10,000"
type: FullTimeEmployee
id: "1"
hours: "37"
duration:
created_at: 2009-06-12 19:16:42

attributes_cache: {}

!ruby/object:TempEmployee attributes:

name: John
updated_at: 2009-06-12 19:19:50
university:
salary: "15,000"
type: TempEmployee
id: "2"
hours:
duration: "5"
created_at: 2009-06-12 19:19:50

attributes_cache: {}

!ruby/object:StudentEmployee attributes:

name: Joe
updated_at: 2009-06-12 19:19:59
university: Queens University, Belfast
salary: "20,000"
type: StudentEmployee
id: "3"
hours:
duration:
created_at: 2009-06-12 19:19:59

attributes_cache: {}

See how the type field has been updated for you?

Now, when we retrieve the employees, we want them to be of the appropriate type. Let's see if this works by getting all employees and calling the "class" method for each.

>> employees = Employee.all

>> employees.each do |employee|
?>    puts employee.class
>> end

Outputs:

FullTimeEmployee
TempEmployee
StudentEmployee

So it works! Yah!

Summary

Single table inheritance is extremely useful for modeling more complex domains. However, it should be used with caution as it can lead to scaling problems.



Posted on Sat 01 Aug 2009 | Comments

Create a Twitter App with Rails: Demo Data

by Phil McClure

Get the Code Using Git!

To get the demo data for the up and coming noupe.com "Create a Twitter App" tutorial you can do the following.

alt text

From the command line, you can grab the code from git hub:

> git clone git://github.com/overture8/Twitter-Blog-Demo.git

If you don't have Git Installed!

Download the code from here and extract it into a folder. Some Simple Configuration Steps

Next, you'll need to update the database.yml file, in the /config folder. Change the password as required.

Now, run some rake commands from the command prompt to create and migrate the database:

> rake db:create

> rake db:migrate

After this is complete you can start up the server to make sure it's all working:

> ruby script/server

That's it! Any questions or issues feel free to leave a comment and I'll get back to you.



Posted on Sat 01 Aug 2009 | Comments

Blueprint CSS Framework

by Phil McClure

There are many tasks that you need to do everytime you start a new web project. Some of these tasks are defining the layout of your website, performing a global reset and typography. The Blueprint CSS framework can be used to ease the pain of repeating these tasks all the time.

Blueprint consists of several CSS files which aim to provide you with a foundation from which you can build upon, resulting in faster, cleaner and less error-prone web developemt.

Layouts are achieved using a grid system, defined by the grid.css file. This is one of the more controversial aspects of this CSS framework. As we have all learnt, HTML should be used to markup data, thats all. CSS should be used to define the layout, however, the grid system seems to push some of this back to the HTML. For instance to define what width a given item is you would code:

The "span-6" attribute value defines that this block will be 6 units in width. Should CSS not be used to define the width of elements?

To be honest, I'm still undecided about how grids achieve their goal. However, I am an advocate of the CSS framework concept. So I hope that people persist with it.



Posted on Wed 01 Jul 2009 | Comments
© 2009 Phil McClure This site was developed using Compass, Blueprint and Ruby on Rails - Much thanks to these guys!