Beginners Tutorial: Routing in Rails 2.0 (with REST) – Part 6 of n

In part 5 we looked at RESTful routing. In this part we continue to explore RESTful routing, by examining nested resources.

I originally planned to cover nested routes and to cover two questions posted to me in previous comments and emails. One question was with regards to ‘one to many relationships’ e.g. an album has many songs. The second question was from Tom in part 3; this was about adding save as functionality.

In trying to answer these questions I created a new application – a text editor with a version history. This has turned out to be a fairly interesting piece of work. I then changed my mind and decided to include it in a follow up post. I am hoping to have that out later this week (before Friday the 11th of July).  As the ‘follow up’ post will have a practical example of nested resources, this post will not have the usual practical section with the experiments.

Part 6

Introduction to Nested Resources

The Nested URI

Returning to the familiar Music Store application, imagine we added songs to the application. Like Albums, Songs are resources and we could expect to access a song with this URI:

/songs/124

We could then perform the required CRUD operations on that URI based on the REST API as discussed in part 5.

An album has many songs. We can express this within the URI e.g.

/albums/10/songs/124

Once again we could make use of the HTTP verbs to perform CRUD in a RESTful way.

In this particular implementation, this URI does not mean that this is the 124th song of album 10 – it is possible for it to be the fist song of album 10.  The URI is pointing to the 124th song in the system.

If we wanted the URI to state the song\track number of the specified album then we could alter the above implementation. Then we could expect to see URIs of:

/albums/10/songs/5
and
/albums/11/songs/5

This would not result in a URI conflict.

Continue reading

Beginners Tutorial: Routing in Rails 2.0 (with REST) – Part 5 of n

Part 6

In part 4 we explored named routes. In this session we move onto Rails’ REST.

Part 5

The Critics

Before we begin you should know that there are many critics of the Rails implementation of REST. There are many reasons for arguments against Rails’ REST e.g. Rails uses server side session state and client side cookies. Some people say that this is not REST compliant. Rails’ REST might not be 100% REST compliant, but you can still benefit from using REST in your Rails applications. In The Rails Way, Obie Fernandez explains that the benefits from using Rails’ REST fall into two categories:

  • Convenience and automatic best practices for you
  • A REST interface to your application for the rest of the world

Therefore it is worth learning and using Rails’ REST.

The Standard Introduction

Representational State Transfer (REST) is an architectural style. It was first introduced by Roy Fielding in his PhD thesis. Roy Fielding is one of the principal authors of HTTP.

The Mindset

When developing a Rails application in the RESTful way it helps to change your mindset. You should not think that you are developing a web site for users accessing the site via a browser. It is better to think of the application as being a service. The service performs actions for clients. These clients may be humans or other machines on the network.

This service will typically be placed on the internet. Therefore we could call it a web service. When I hear the term web service I immediately start thinking about SOAP and all the WS-* specifications. Let’s be clear, we are not talking about ‘those’ web services. We are talking about RESTful web services. These two technologies provide similar functionality, but RESTful web services are simple and sensible.

The Terminology

As previously stated, programming in REST requires a change in the way we think about the system. This naturally leads to a change in the way we talk about the system. The following provides a brief description of some of the key terms used in discussions about REST and HTTP.

A resource is one of the key concepts in REST. Many discussions on REST claim that a resource is anything and everything. This is neither true nor helpful. Let’s examine this concept with the aid of an example.

Let’s assume that the music store has started selling albums. The database may have the following schema:

orders erd

The data in the database is the raw data. There is data which, given in isolation, is of no real value to a client. For instance it is unlikely that a client will want only one row from the LineItems table. This means that a LineItem (on its own) is not a resource within the context of the music store service.

A client would want all the information pertaining to an order. This would include data from one or more tables. Some data would not be included e.g. database keys. Some information may be added e.g. the total cost of the order might be calculated and included in the ‘order information’. This ‘order information’ is an example of a resource. Order resource is the type, there will be one order resource instance for each order made.

Each resource must be given a globally unique identifier. This is done using a URI. This could look like this:

http://www.example.com/orders/65

A client, in an admin role, may want a list of all the orders. This collection of orders would be another resource. Following the REST architecture, the orders resource would be assigned the following URL:

http://www.example.com/orders

It is important to note that these resources are not HTML documents. Roy Fielding describes a resource as a conceptual mapping. As a resource is a conceptual entity it can not be used by a client. The service provides the client with a representation of the resource.

When the client is a browser, the service typically provides an HTML representation of the resource. If the client is another machine then the service may provide an XML representation of the resource. Other representations could include a PDF file, an image, csv etc. A representation is only supported by the service if it is applicable and required.

Resources are often referred to as nouns. This is often done when talking about HTTP to assist learning. The term ‘noun’ is more abstract. For our purposes, resources and ‘nouns’ are synonymous.

HTTP also has the notion of verbs. These are the HTTP operations. We are all familiar with the POST and GET operations. In addition to these two operations, HTTP also supports: DELETE and PUT.

There are a few more terms to cover, but we can do that later. The core terms have been explained.

Continue reading

Beginners Tutorial: Routing in Rails 2.0 (with REST) – Part 4 of n

Part 5

The routes we have discussed so far are known as simple routes. I have been referring to them as custom routes, but ‘simple routes’ is the correct term. The default route we discussed in part 3 is also a simple route. The aim is to move onto RESTful routes, sometimes called resource routes. RESTful routes are built on top of named routes. Therefore we must first cover named routes, and that is what part 4 is all about.

Part 4

Introduction

Referring back to part 1, the routing system has two main functions:
Interpreting a request URL
Generating a request URL

We had a detailed look at route generation and interpretation in part 2, but let’s have another quick look at it. Let’s assume, for some insane reason, that we defined the following route in the music_store routes.rb file:

map.connect ‘apples/bananas/:id’, :controller => “albums”, :action => “show”

link_to would use this rule to generate a URL, this can be seen in the following line extracted from index.html.erb:

link_to ‘Show’, :controller => “albums”, :action => “show”, :id => album.id

This could generate a URL of: http://localhost:3000/apples/bananas/7
And when given this request, Rails would handle it correctly e.g. the show action will be called on the albums controller and the show view will be sent as the response to the browser.

Coming back to the real world, we are more likely to define the routing rule like this:
map.connect ‘albums/show/:id’, :controller => “albums”, :action => “show”

link_to (and friends) would then generate a URL like this:
http://localhost:3000/albums/show/7.

To show the index (the listing of the albums) we could define a rule like this:
map.connect ‘albums/index’, :controller => “albums”, :action => “index”

The matching link_to in edit.html.erb is:
link_to ‘Back’, :controller => “albums”, :action => “index”

Looking at the last example, there is some repetition. Both lines contain:
:controller => “albums”, :action => “index”

The link_to method needs this (controller, action) information to obtain the URL. If we had the URL stored as some global variable, or method, then we could simply pass that into link_to. link_to could use this ‘literal’ URL without needing to generate one.
This could look something like: link_to ‘Back’, albums_index_url
This is one of the main ideas behind named routes.

Continue reading

Beginners Tutorial: Routing in Rails 2.0 (with REST) – Part 3 of n

Part 4

Part 3

At the end of part 2, routes.rb looked like this:

ActionController::Routing::Routes.draw do |map|
  map.connect 'music', :controller => "albums", :action => "index"
  map.connect '', :controller => "albums", :action => "index"
  map.connect 'music/show/:id', :controller => "albums", :action => "show"
  map.connect 'music/delete/:id', :controller => "albums", :action => "destroy"
  map.connect 'music/edit/:id', :controller => "albums", :action => "edit"
  map.connect 'music/update/:id', :controller => "albums", :action => "update"
  map.connect 'music/new', :controller => "albums", :action => "new"
  map.connect 'music/create', :controller => "albums", :action => "create"
end

To simplify things, let’s remove the routing rule for the empty URL. Remove line 3.

We can no longer browse to http://localhost:3000/, but we can still browse to http://localhost:3000/music. Besides that, the site should continue to work as before.
Looking at the routes.rb file we see 7 rules defined.

ActionController::Routing::Routes.draw do |map|
  map.connect 'music', :controller => "albums", :action => "index"
  map.connect 'music/show/:id', :controller => "albums", :action => "show"
  map.connect 'music/delete/:id', :controller => "albums", :action => "destroy"
  map.connect 'music/edit/:id', :controller => "albums", :action => "edit"
  map.connect 'music/update/:id', :controller => "albums", :action => "update"
  map.connect 'music/new', :controller => "albums", :action => "new"
  map.connect 'music/create', :controller => "albums", :action => "create"
end

We have 7 rules and only one database table. Does this mean we need to add 7 more rules for every table we add? No, there are ways to reduce the amount of explicitly defined rules.

When Rails receives a URL it tries to find a matching routing rule. It does this by comparing the URL to the pattern string in the rule.
The pattern string for map.connect ‘music/create’, :controller => “albums”, :action => “create” Is: music/create

The pattern string for map.connect ‘music/edit/:id’, :controller => “albums”, :action => “edit”
Is: music/edit/:id

The :id is a Ruby symbol and is referred to as a receptor. If you are new to Ruby you may not be too familiar with symbols. I once came across a short and sweet description of a symbol “A symbol is the name badge, not the person”. I may have read that in here.

A receptor is used as a wildcard. It matches anything that it is compared against. The wildcard receptor gets passed into the controller action within the params hash e.g.

def edit
    @album = Album.find(params[:id])
end

You can change :id to almost anything as long as you remember to change it in the controller and in the views where the URL is generated e.g. when using link_to. I recommend you use :id as that is the convention.

Continue reading

Beginners Tutorial: Routing in Rails 2.0 (with REST) – Part 2 of n

Part 3

Thank you to all of you who took the time to give me feedback on part 1. Most of the feedback was positive. A friend of mine suggested that I drop the sound effects and stick to the subject matter, I graciously accepted his advice. Therefore this post should have a better fact to fluff ratio than the previous one. On that note, let’s begin…

Part 2

In part 1 we learnt that the routing system has two main functions:
• Interpreting a request URL
• Generating a request URL
Rails uses the same routing rule to interpret a URL and to generate a URL.
Note that routing rules are often called routes, I will use the terms interchangeably.

Now we will start fixing our music_store application from part 1.

Continue reading

Beginners Tutorial: Routing in Rails 2.0 (with REST) – Part 1 of n

Part 2

About this series

This is a series for beginners wanting to learn about routing in Rails 2.0. This first post is aimed at exploring the behaviour of routing in Rails. It examines what happens when the routing system is given a certain URL. Future posts will examine the ‘hows’ and ‘whys’ of this behaviour. The plan is to start with the basics and move towards the advanced topics. There is only a brief mention of RESTful routing in this post. I plan to delve deeper into that topic at a later stage.

Introduction

The routing subsystem is at the heart of a Rails application. By looking at the following image, we can see the role of the routing system.

RoutingInRails

The diagram is a modified version of a diagram found in Flexible Rails.

As the picture depicts, in a Rails application the process begins with a request from the browser. This request is passed into the Rails routing system. The routing system examines the request and is able to determine the following information:

  • Which controller to instantiate
  • Which action (method) to invoke on that controller
  • The parameters, if any, to pass into the action

When receiving a correctly formatted request URL the routing system will instantiate the specified controller, call the appropriate action and pass in the supplied method parameters, if required. The controller will then perform the necessary action and Rails will render the relevant view. This will result in the browser receiving a response and the round trip is complete. This is oversimplified, but it does show the importance of the routing system.

If the request is not in the correct format the routing system may not be able to infer the correct action to take. Therefore it is important that the format is correct. We are in luck as the Rails routing system also helps us to generate requests in the correct format.

In short, the routing system has two main functions:

  • Interpreting a request URL
  • Generating a request URL

The routing system performs these functions by using routing rules, defined in Ruby code as opposed to XML. The rules can be found in the config/routes.rb Ruby file. Each rule is used to both interpret and to generate a related request URL.

I could go into more theory here but, as with many things, the best way to get to grips with routing is to do it!

Continue reading