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:
rails
command.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.
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:
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.
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.
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:
In the example script, the model role is performed by the section of code which saves the email address into a text file.
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.
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.
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.
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:
Fleshing out the steps in the diagram, here's what happens when a client requests a list of people:
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.
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.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.)
Person
instances and returned to the controller. 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.
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:
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. 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.
3.145.35.194