The Action Pack library for Rails handles the chain of events that starts when a user makes a request to a Ruby-on-Rails application. This article series gives you an overview of the library, and then walks you through using it in a sample application. It's excerpted from chapter six of the book Beginning Rails: From Novice to Professional, written by Jeffery Allan Hardy, Cloves Carneiro Jr. and Hampton Catlin (Apress; ISBN: 1590596862).
Controllers orchestrate your application’s flow. Every time a user requests a page, submits a form, or clicks a link, that request is handled—in one way or another—by a controller. When you’re programming your application, you spend a lot of your time building controllers and giving them instructions on how to handle requests.
The concept of controllers can sometimes be difficult for newcomers to grasp. Even if you’ve built web applications before, say in ASP or PHP, you might not be used to this form of separation, where the mechanics of flow are controlled by a separate entity and not embedded in the pages themselves.
Let’s look at the example of the CD player in your car to illustrate the concept of controllers. The player is required to respond to certain events, such as pressing the Play button, fast forwarding, or rewinding a track. When you push a button, you expect something to happen—you’ve made a request, and you wait for the subsequent response.
If your CD player were a Rails application, the instructions for what to do when a certain event takes place, such as the pressing of the Eject button, would be contained in a controller. If you were to sketch it out on paper, it might look something like this:
These events, or actions, describe what the player should be capable of doing. Obviously, each of these actions would need to be programmed to do something with the disc that’s inside the player. When someone presses Eject, you would first call on the stop action (if the disc is playing), and then arrange for the player to spit out the disc. You would code all the instructions for dealing with an eject event into the controller—specifically, inside the eject action. The same would apply for play, fast-forward, and rewind.
It’s worth noting that this type of logic has nothing to do with the CD itself, nor does it have anything to do with the music on the CD. If this were a Rails application, the CD would be the model. It can be used independently of the player. In fact, it can be used in all sorts of players, not just the one in your car.
The stereo in your car is probably capable of more than just playing CDs. Most have a radio receiver built in as well. The radio would have its own set of events that would likewise need to be handled. These actions might include things like changing stations, setting presets, and switching between AM and FM. To keep things well organized, you would probably want to group these actions inside their own controller, separate from the CD controller. After all, the radio and the CD player do different things.
When you’re dealing with a Rails application, it’s not much different. You separate the things that you need your application to do with an object from the object itself. Even when you’re not dealing directly with an object (adjusting the volume on your car stereo has little to do with either the CD in the player or the station on the radio), you still handle the event inside a controller.
Each controller in Rails is designed as a Ruby class. Without getting too technical, here’s how the CD player example would look if it were a Ruby class:
class CDPlayer def play end
def stop end
def fast_forward end
def rewind end
def eject end end
Inside theCDPlayerclass, we’ve defined a method for each action, or each thing we want our CD player to be able to do. So, if we were to send the message “play” to an instance of theCDPlayerclass, it would know how to handle it (of course, since theplay method is empty in our example, nothing would happen). On the other hand, if we sent the message “pause,” Ruby would raise an exception and tell us that the method was not found. If we wantedCDPlayer objects to respond to that message, we would need to add a method called (you guessed it)pause.
All the methods in this class are public, which means that they can be invoked by anyone. We don’t need to do anything special to a method to make it public. Unless otherwise declared, all methods in a Ruby class are public by default. If we were to mark an action as private, though, it could be used only internally by the class. For example, if thestopmethod were private, it would raise aNoMethodErrorif we called it from outside theCDPlayer class. However, theeject method is free to call onstop, because it does so internally. While the usefulness of this feature will become apparent as you continue to learn about controllers, consider this: if your CD player needed to display the time remaining for a given track, it might need to perform a few calculations to figure that out. You might create a method for doing these internal calculations, but would you want that method to be accessible from the outside? Would you have a button called Calculate on your player?
It’s time for a working definition: Action Controllers are Ruby classes containing one or more public methods known as actions. Each action is responsible for responding to a request to perform some task. A typical controller is most often a collection of actions that relate to a specific area of concern. For example, consider the events application we’ve been building in the previous chapters. The controller that manages events has the class nameEventsControllerand has action methods for listing, creating, reading, updating, and deleting events.
While our example of the CD player worked well to illustrate the basic concept of controllers, it won’t take us much further when dealing with web applications. If we were really dealing with a CD player, we would press Play, the disc would start playing, and that would be the end of it. But since Rails was specifically designed for building web applications, it makes a fair number of assumptions about what we want our actions to do when they’re finished firing. Chief among these is the rendering of a view.
Imagine that you’re reading a list of posts on someone’s blog. You click the title of a post, and you expect to be taken to a new screen that shows you just that post. You requested an action (show), and in response, you’ve received a new screen. This happens all the time in the world of web applications: when you click a link, you expect to go to a new page.
In Rails, it is the general case that when actions have completed their work, they respond by rendering a view. In fact, the concept of actions rendering views is so common that Rails has internalized it as a convention: unless otherwise stated, when an action is finished firing, it renders a view. How does Rails know what view to render if you don’t tell it? It looks for a view whose name matches that of the requested action. This should give you some insight as to why Action Controller and Action View are bundled together in Action Pack. Because of the way controller actions relate to views, a few other mechanisms facilitate their communication, all of which we’ll cover shortly.
Please check back for the next part of this series.
DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware.