Chapter 4. Working with Rails

It's now time to get our hands dirty and start developing a Rails application. In Chapter 2, we saw the data structure for the Intranet application, which Acme plans to build. In this chapter, we'll start building this application: in effect, we will be looking over Rory's shoulder as he develops Intranet. For the purposes of this chapter, Linux will be used as the development platform; but as all of the tools used are cross-platform, the instructions should port easily to Windows and Mac.

Specifically, we'll focus on turning the abstract data structure for Intranet into a Rails application. This requires a variety of concepts and tools, namely:

  • The structure of a Rails application.
  • Initializing an application using the rails command.
  • Associating Rails with a database.
  • The built-in utility scripts included with each application.
  • Using migrations to maintain a database.
  • Building models and validating them.
  • Using the Rails console to manually test models.
  • Automated testing of models using Test::Unit.
  • Hosting a project in a Subversion repository.
  • Importing data into the application using scripts.

You may have noticed that we haven't mentioned much about the application's user interface. That's because we can build a large part of the application without having to code HTML. We'll see how to add a front-end in the next chapter, but for now we will concentrate on the data side of things.

The World According to Rails

To understand how Rails applications work, it helps to get under its skin: find out what motivated its development, and the philosophy behind it.

The first thing to grasp is that Rails is often referred to as opinionated software (see http://www.oreillynet.com/pub/a/network/2005/08/30/ruby-rails-david-heinemeier-hansson.html). It encapsulates an approach to web application development centered on good practice, emphasizing automation of common tasks and minimization of effort. Rails helps developers make good choices, and even removes the need to make choices where they are just distractions.

How is this possible? It boils down to a couple of things:

  1. Use of a default design for applications-

    By making it easy to build applications using the Model-View-Controller (MVC) architecture, Rails encourages separation of an application's database layer, its control logic, and the user interface. Rails' implementation of the MVC pattern is the key to understanding the framework as a whole.

  2. Use of conventions instead of explicit configuration-

    By encouraging use of a standard directory layout and file naming conventions, Rails reduces the need to configure relationships between the elements of the MVC pattern. Code generators are used to great effect in Rails, making it easy to follow the conventions.

We'll see each of these features in more detail in the next two sections.

Model-View-Controller Architecture

The original aim of the MVC pattern was to provide architecture to bridge the gap between human and computer models of data. Over time, MVC has evolved into an architecture which decouples components of an application, so that one component (e.g. the control logic) can be changed with minimal impact on the other components (e.g. the interface).

Explaining MVC makes more sense in the context of "traditional" web applications. When using languages such as PHP or ASP, it is tempting to mix application logic with database-access code and HTML generation. (Ruby, itself, can also be used in this way to write CGI scripts.) To highlight how a traditional web application works, here's a pseudo-code example:

# define a file to save email addresses into
email_addresses_file = 'emails.txt'
# get the email_address variable from the querystring
email_address = querystring['email_address']
# CONTROLLER: switch action of the script based on whether
# email address has been supplied
if '' == email_address
# VIEW: generate HTML form to accept user input which
# posts back to this script
content = "<form method='post' action='" + self + "'>
<p>Email address: <input type='text' name='email_address'/></p>
<p><input type='submit' value='Save'/></p>
</form>"
else
# VIEW: generate HTML to confirm data submission
content = "<p>Your email address is " + email_address + "</p>"
# MODEL: persist data
if not file_exists(email_addresses_file)
create_file(email_addresses_file)
end if
write_to_file(email_addresses_file, email_address)
end if
print "<html><head><title>Email manager</title></head>
<body>" + content + "</body></html>"

The highlighted comments indicate how the code can be mapped to elements of the MVC architecture:

  • Model components handle an application's state. Typically, the model does this by putting data into some kind of a long-term storage (e.g. database, filesystem). Models also encapsulate business logic, such as data validation rules. Rails uses ActiveRecord as its model layer, enabling data handling in a variety of relational database back-ends.

    In the example script, the model role is performed by the section of code which saves the email address into a text file.

  • View components generate the user interface (e.g. HTML, XML). Rails uses ActionView (part of the ActionPack library) to manage generation of views.

    The example script has sections of code to create an appropriate view, generating either an HTML form for the user to enter their email address, or a confirmation message acknowledging their input.

  • The Controller orchestrates between the user and the model, retrieving data from the user's request and manipulating the model in response (e.g. creating objects, populating them with data, saving them to a database). In the case of Rails, ActionController (another part of the ActionPack library) is used to implement controllers. These controllers handle all requests from the user, talk to the model, and generate appropriate views.

    In the example script, the code which retrieves the submitted email address, is performing the controller role. A conditional statement is used to generate an appropriate response, dependent on whether an email address was supplied or not.

In a traditional web application, the three broad classes of behavior described above are frequently mixed together. In a Rails application, these behaviors are separated out, so that a single layer of the application (the model, view, or controller) can be altered with minimal impact on the other layers. This gives a Rails application the right mix of modularity, flexibility, and power.

Next, we'll see another piece of what makes Rails so powerful: the idea of using conventions to create associations between models, views, and controllers. Once you can see how this works, the Rails implementation of MVC makes more sense: we'll return to that topic in the section Rails and MVC.

Convention over Configuration

In the previous section, we met the MVC framework, used to define the general design of every Rails application. The MVC framework naturally breaks an application into three groups of components (models, views, and controllers). In the "olden" days, a web application framework would typically define relationships between these components using a configuration file (e.g. an XML file in the Struts framework). Writing this configuration file was often a laborious and error-prone task, and could take the same amount of time as writing the application code itself.

The Rails developers recognised that, most of the time, the relationships between the parts of an MVC application are obvious, repetitive, and shouldn't require configuration. There tends to be a common set of actions associated with each controller ("show a list of model instances"; "show a single model instance"; "create, update, or delete a model instance"); and developers will tend to give them similar names (list, show, delete, update, create). This realization prompted the Rails developers to create a set of conventions around how common application components are implemented: standards for class names and locations, controllers and actions, file names, and directory structure.

Rail uses these conventions to minimize the need for configuration, automatically generating much of it when the application is bootstrapped. As well as simplifying configuration, the conventions also remove the need for a developer to make certain decisions. In classical web applications, a developer would often have to decide where to put files and directories, and then have to define relationships between application elements (e.g. which views are used by which controller). By contrast, every Rails application has a familiar directory structure, automatically generated by tools; each file added to the project usually adheres to a naming standard; classes follow a similar naming convention; and there are conventions for naming and

locating supporting files, like Javascripts and images. By making choices for the developer, Rails can save time (and sometimes arguments), leading to its much-touted productivity gains.

Note

If you need to, you can step outside the Rails conventions. Mostly, though, there is no need to, and you can greatly reduce development time by embracing the conventions instead.

Rails and MVC

At its core, the architecture of Rails is standard MVC; however, unlike older forms of MVC for the web, Rails minimizes the effort needed to maintain the MVC pattern. This is because the conventions inherent in Rails, as described in the previous section, reduce the need for configuration. The diagram, below, gives a graphical representation of how Rails implements MVC, and also summarizes how conventions are used to define the workflow of an application. Our fledgling Intranet application is used as an example; specifically, the page which displays a list of people:

Rails and MVC

Fleshing out the steps in the diagram, here's what happens when a client requests a list of people:

  1. The client asks for the URL:/people/list.
  2. Rails' routing code parses the URL into a request for a particular controller, and a particular method on that controller. In this case, Rails uses a typical route to fragment the path into a controller name (people) and the name of a method on that controller (list). In this case, the following sequence is executed:

    a. An instance of the PeopleController class is created. Rails knows to generate an instance of this class, as it uses the first part of the path (= people), capitalised (= People), and with the string 'Controller' appended (= PeopleController), to determine the correct controller class to use. This returns a PeopleController object (which will be referred to as "the controller" from now on). This is followed by:

    b. A call to the list method (a.k.a. an action) of the controller. Again, the path is used to determine, which method to call: in this case, the second fragment of the path is list; hence Rails calls the list method.

    The routing facilities in Rails are covered in more detail in the section on routing in Chapter 7.

  3. The list action of the controller uses the find method of the Person model class to query the database. Each model class provides a find method, which enables querying of the table associated with the model. Find methods are covered in more detail in the section on find methods in Chapter 5.
  4. The Person class is, by convention, associated with a table called people. The Person class, therefore, generates the SQL required to retrieve a set of records from the people table in the back-end database.

    Note how the table name is the pluralized, lowercase equivalent of the model class name: Person associates with people; Address associates with addresses; Company associates with companies; etc. These relationships don't have to be specified: they are configured solely through consistent names. (It is also possible to turn pluralization off, if you want to buck these conventions.)

  5. The set of records is converted into an array of Person instances and returned to the controller.
  6. The controller uses a view template to create the output for the client. This output will typically be based on an HTML outline, filled out with data from the model. In our example, the template might produce an HTML table from the array of Person instances, one row per person, showing the name of the person and a link to their full details.

    The name of the template to render for a given action is derived by convention (again), and is based on the name of the action: in this case, the action is called list, so Rails uses a template called list.rhtml. If there is no appropriate .rhtml file, Rails will look for a .rxml (Builder XML template) file instead. Views are covered in more detail in chapter.

  7. The controller returns the generated HTML to the client.

As you can see, the Rails conventions enable some powerful connections between aspects of the model, view, and controller components, with no need for configuration.

The Rails "power tools" are the keys to leveraging its conventions, namely:

  • The rails command. This creates the "skeleton" for an application, including the directory structure, public files (like error pages and Javascripts), stubs for automated testing, plus several utility scripts. The created directories and files follow the conventions described previously.
  • The Rails generators. These are included with the utility scripts, and added to every new Rails application created using the rails command (see above). They are used to add new components to the application, such as new models or controllers, again following the naming conventions.

We'll see how to use these tools in the following sections, as we start building the Intranet application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.35.194