Monday, June 21, 2010

Ruby at ThoughtWorks


This is Article is Originally published in http://martinfowler.com by martin flower

he Explains how Ruby fits into there Organization.

ThoughtWorks, my employer, is primarily a software delivery company. We build software for people, including products built for ourselves. An important part of our philosophy is an openness to to different development platforms, so we can choose the appropriate platform for our widely varying clients. When I joined ThoughtWorks in 2000, Java was our overwhelmingly major platform. Shortly afterwords we started working with .NET and these two platforms dominated our work by the middle of the decade.

A few people, however, had started experimenting with LAMP scripting languages, in particular Ruby. The appearance of the Ruby on Rails web framework gave Ruby a big push, enough that in 2006, we started doing some serious project work with the Ruby platform. As I write this in 2009, the Ruby platform has a firm share of our work, not as high as Java and C#, but a significant portion.

During these three years we've learned a lot about Ruby in practice. As 2009 began, I was asked to give a talk on our experiences with Ruby for the QCon conference. To prepare for this I conducted an extensive survey of our Ruby projects and probed our Ruby leaders for their thoughts and experiences. It's taken me a bit longer than I'd like to produce this article as well, but here it is.

I've divided the article into three parts. To start with I'll look at the profile of our Ruby project experience, to give you a sense of what kinds of projects we've been tackling over the years. Next I'll move onto several common questions about Ruby and how our experiences answer these questions. Finally I'll launch into some lessons we've learned from using Ruby.

The Shape of Our Projects

During 2006-8, ThoughtWorks has been involved in some 41 Ruby projects. I define a Ruby project as a project where Ruby was the primary development language. Ruby has appeared on other projects too, there's a lot of recent developments using ruby for build automation or functional testing for Java projects. Almost all these projects have involved Rails, and most of them are web site projects where Rails is at least as important as Ruby.

Figure 1

Figure 1: Scatterplot of peak headcount versus involved length for ThoughtWorks Ruby projects in 2006-8.

Figure 1 gives a feel for the size of the projects we've been involved in. The headcount here is the peak headcount of everyone involved (ThoughtWorks, client and others; developers, project managers, analysts etc). The length is the duration that we've been involved in the project.

Ruby projects are generally seen as shorter and smaller than other projects. Sadly I don't have comparative data for our projects on other platforms to get a better feel on whether this is true. Certainly we can see that most projects involve less than 20 people for less than a year.

There are a few projects that stand out. By far our largest project is the one that I'll refer to as the Atlanta project, with a peak headcount of over 40 people involved. Another large and long running project is the Jersey project. These two are related in that there's been a good bit of rotation between the two, so many of our more experienced Ruby people have been on both projects.

The third project I've called out here is Mingle, which is a particularly interesting case as it's a product from ThoughtWorks Studios - and as such we can be more public about it than we can about projects done for clients. It's been a long running project and also an international project: starting in Australia, moving to Beijing, and now multi-sited in Beijing and San Francisco.

Figure 2

Figure 2: Strip chart showing effort for project for each year.

Figure 2 looks at the shape a different way, looking at the effort involved in the various projects we've been involved in for each year. Each dot on the strip chart represents total effort (all people) in one project during that year. This chart provides a good feel for how much increase we've seen in ruby projects over the last three years.

Figure 3

Figure 3: Strip chart showing project effort per host country

Figure 3 looks at the projects by host country. It's somewhat rough and ready, as I haven't tried to properly deal with the few multi-site projects or projects that have moved (Mingle, for example, I classed as a China although it's history is more varied.)

The country split shows that the US has seen the biggest interest in Ruby work. India has also seen a fair amount - indeed our first Ruby project was run out of Bangalore. The UK has seen less uptake. This probably reflects the fact that our early Ruby advocates were mostly US based and there was considerable skepticism to Ruby in the UK. The level of involvement from India is encouraging, traditionally India is seen as a laggard in using new technologies but we seem to be doing a reasonable job of making our Indian offices be rather different.

Our experience selling Ruby work is that using a dynamic language like Ruby fits in well with our overall appeal. Our strength is that we hire highly talented people who are difficult to attract to the typical IT organization. Ruby has a philosophy of an environment that gives a talented developer more leverage, rather than trying to protect a less talented developer from errors. An environment like Ruby thus gives our developers more ability to produce their true value.

Ruby also fits in with our preference for using agile software development processes. The agile philosophy is one of rapid feedback by building software and reviewing it regularly with the customer. The more productive an development environment, the more frequently you can review progress, and the better the agile "inspect and adapt" process works.


Questions About Ruby

Was Ruby the Right Choice?

When looking back on our 41 projects, perhaps the most important question to ask is whether the Ruby platform was the correct choice. One way to approach that question is to ask technical leads on the project whether, in hindsight, they think the choice was correct.

Figure 4

Figure 4: Was Ruby the correct choice of platform for this project?

As Figure 4 indicates, the vote was a very positive 36 to 5 support of the choice. As a group our technical leads are usually not shy of indicating if they are unhappy with a technological choice. So I see this as a firm statement of the viability of the Ruby platform as a reasonable choice.

I dug a little more into the five regretful projects. The first thing that stood out was that in four of the five cases, the leads felt that using Ruby wasn't a worse choice than the alternatives. Ruby's relative unusualness means that we feel that using Ruby has to come with a benefit over alternatives, if Ruby is the same as a more widely used option, then it isn't worth introducing the unusual technology. Four of the five also reported problems due to integration with other technologies that Ruby isn't as well suited for. .NET tools tend to integrate better with .NET technologies, for example. Another theme that two of the projects reported was social issues - that people in the client organization were opposed to Ruby or other dynamic languages. The one worse-off project showed these social problems - an IT organization that resisted Ruby tooth and nail (the business sponsor in this case was a Ruby fan).

Indeed when I asked further about red flags for using Ruby in software project, the only clear answer was around social issues. Ruby was generally accepted or encouraged for our software development work, but the biggest sign to avoid it was a social resistance from the client.

Is Ruby More Productive?

When people are asked about why Ruby should be used on a project, the most common answer is for increased productivity. One early indicator was an assessment of a project that suggested that Ruby would have yielded an order of magnitude improvement in productivity.

As a result it seemed obvious to survey the project technical leads and ask them about productivity - had ruby increased productivity and if so, by how much. I asked them to compare this to a mainstream (Java or .NET) project done in the most productive way they knew how.

Figure 5

Figure 5: How much did Ruby improve productivity for this project? (Compared to the best mainstream tools you know.)

You should take these result with some salt. After all there is no way we can objectively measure software productivity. These are just the subjective, qualitative assessments from the technical lead of each project. (I didn't get a response from all projects.) However they are still suggestive that there's a real productivity boost going on.

This suggestion is further reinforced by staffing considerations. Scott Conley, who manages our Atlanta office, reports that once a ruby project has got going, he expects them to need 50% more people whose focus is on requirements preparation than would be expected for other technologies.

One thing we have seen is that you shouldn't expect these productivity increases to turn up right away. I've heard several times that people were alarmed in early weeks about the slow progress of a new Ruby team - a consequence of what I call the Improvement Ravine. It does take time for a Ruby team to get the hang of how the platform works and during that time they'll be slower than you expect.

The improvement ravine is a common phenomenon and a usual palliative is to ensure there are some experienced people on the team. Our history, however, is that the most important experience here is that of dynamic languages that support the kinds of meta-programming features that Ruby does, rather than specifically Ruby experience. As Scott Conley puts it: the difference is between efficiency risk and delivery risk. A team with dynamic language experience but little Ruby experience will be slower initially (efficiency risk) but a team without any dynamic language experience can produce a knotty code base that could risk the overall delivery.

Is Ruby Slow?

In a word "yes". Search around for benchmarks on the net and you'll find numerous surveys that show that, even by the standards of scripting languages, Ruby is a tortoise.

On the whole, however, this has been irrelevant to us. Most of our uses of Ruby are in building database backed websites. I've visited many projects over the decades like this, using Ruby and other technologies, nearly every project has spent time working on performance issues and in almost every case those performance issues are database access. People spend time tuning SQL not tuning their processing code. So since most applications are I/O bound, the use of a slow language for processing doesn't make any appreciable impact to the overall performance of a system.

You'll notice I've used the usual pundit weasel words in the above paragraph. Although almost every project is I/O bound, you do run into the occasional exception - and an interesting one is Mingle. Mingle is unusual in many ways. It's very dynamic display means it can't use any page caching to improve performance, which immediately makes it unlike most web applications. As a result it isn't I/O bound and for good performance needs more hardware than many people expect (a four core box with 2GB of memory to support a 20-40 person team).

But the Mingle team still feel they made the right choice in using Ruby. The Mingle team has built many features very quickly and they feel the productivity boost they got from Ruby is worth the higher hardware demands on the final product. As with so many things, this is a hardware versus productivity trade-off - one of the oldest trade-offs in computing. Each team needs to think about which matters. The good news here is that Mingle has good horizontal scalability (throw more processors at it and you get proportionally good performance). Hardware scalability is often the most valuable thing you can have in these situations as hardware costs keep declining.

I should re-emphasize. For most projects Ruby's speed has been irrelevant as almost all of them are I/O bound. Mingle is an exception, not the common case.

Is a Ruby Code-base Hard to Understand?

A concern we frequently hear about Ruby is that its dynamic typing, support for meta-programming, and lack of tools makes it liable to leave a code base that's difficult to follow. In general this hasn't turned out to be a issue in practice for us. The story I hear is that the fact that you can write much less code for the same functionality means that it's easier to keep the code clean than it is for mainstream languages.

That said, it's important to remember our context. ThoughtWorks developers tend to be far above average in terms of ability and also very keen on highly disciplined approaches, such as Extreme Programming. We place a high value on testing (something that's true of the Ruby community generally) and these tests do much to keep the code base clear. So I can't say whether our experiences will carry over to less able and disciplined developers. (Even the tooling and relative control of other languages doesn't stop us from seeing some pretty horrible code, so it's open to question whether a poor Ruby code base would be that much worse.)

We have seen a common sequence of attitudes to meta-programming.

Figure 6

Figure 6: Progression of feelings about meta-programming

  • Scary and Bad: People are wary of meta-programming and don't use it much
  • Scary and Good: people begin to see the value of meta-programming but are still uncomfortable with using it.
  • Easy and Good: as people get comfortable they begin to use it too much, which can complicate the code-base.
  • Easy and Bad: people are wary of meta-programming and realize that it's very useful in small doses.

In the end the analogy I like best for these kinds of techniques is that they are like prescription drugs. They are very valuable in small amounts but you need to ensure that you don't overdose.

As with many things, experience is the great helper here as it can get you through this curve more rapidly. In particularly it's important to expect this adoption curve, particularly the over-usage. When learning something new it's common to over-use it at some stage because without crossing the line it's hard to know where that line is. It can also be useful to try and build a sandbox - a relatively contained area of the code-base for people to overdo the meta-programming in. With a suitable sandbox it's easier to undo the over-usage later on.

Is Ruby a Viable Platform

All of these questions sum up into the key question for us: is Ruby (and Rails) a viable platform for us and our clients. The answer thus far is a resounding "yes". It offers palpable gains in productivity, allowing us to be more responsive and produce better software, more quickly for our clients. This isn't to say it's the right choice for all situations. Choosing a development platform is never a simple choice, particularly since it usually is more of a social choice than a technological choice. But the headline conclusion is that Ruby is a choice that's worth considering, worthy enough for us to want to keep this tool in our toolkit.

An interesting side question here is the role of other less-common languages. Should we be using Groovy, F#, Python, Smalltalk, and others? I wouldn't be surprised if many of the same trade-offs we see for Ruby are true also for these other languages. I hope we'll see some of these added to our toolkit in the future.

I should also stress that it isn't a case of either/or when it comes to using these languages and the mainstream Java/C# options. I've always advocated that development teams using a language like Java/C# should also use a scripting language for various support tasks. Ruby makes an excellent choice for this, and we are seeing this combination increase on our projects. With the rise of support for these languages on the JVM and CLR, we see more opportunities to intermix different languages with different strengths - an approach Neal Ford refers to as Polyglot Programming.


Some Development Tips

In this last section, I'll run over a grab-bag of lessons we've learned from using Ruby.

Testing with Active Record

Right at the beginning of our use of Ruby, there was a debate on how best to organize testing in the presence of the Active Record database layer in Rails. The basic problem is that most of the time, performance of enterprise applications is dominated by database access. We've found that by using a Test Double we can greatly speed up our tests. Having fast tests is crucial to our test-intensive development process. Kent Beck recommends a basic commit build of under ten minutes. Most of our projects manage this these days, and using a database double is a vital part of achieving it.

The problem with Active Record is that by combining database access code with business logic, it's rather harder to create a database double. The Mingle team's reaction to this was to accept that Rails binds the database tightly and thus run all the commit tests against a real database.

The contrary view was advocated most firmly by the Atlanta and Jersey teams. Ruby has a powerful feature that allows you to redefine methods at run-time. You can use this to take an active record class, and redefine the the database access methods in that class as stubs. The team started the gem unitrecord to help with this.

In the three years, we've not seen a generally accepted victor in this debate. The Mingle team run a couple of thousand tests against a real postgres database in around 8 minutes. (They parallelize the tests to make use of multiple cores.) The Atlanta and Jersey teams consider it valuable that their commit test runs in 2 minutes with stubs versus 8 minutes without. The trade-off is the simplicity of the direct database tests versus the faster commit build of the stubbed tests.

While both teams are broadly happy with their positions in this debate, the use of stubbing has led to another issue for the Atlanta/Jersey teams. As the teams became familiar with using method stubbing, they used it more and more - falling into the inevitable over-usage where unit tests would stub out every method other than the one being tested. The problem here, as often with using doubles, is brittle tests. As you change the behavior of the application, you also have to change lots of doubles that are mimicking the old behavior. This over-usage has led both teams to move away from stubbed unit tests and to use more rails-style functional tests with direct database access.

Active Record Leaks

A common situation that people report is time spent futzing with SQL. Active Record does a good job of hiding much database access from the programmer, but it fails to hide it all - essentially the abstraction leaks. As a result people have to spend a reasonable amount of time working with SQL directly.

This leakiness is a common feature of object/relational mapping frameworks. Pretty much every time I talk to people on a project, they'll say that the O/R mapping framework hides the SQL efficiently about 80-90% of the time, but you do need to spend some time working on SQL in order to get decent performance. So in this respect Active Record is really no different from any other O/R mapper.

Indeed one comment I do hear is that with Active Record, the abstraction breaks cleanly. When chatting with DHH, he's always stressed that he believes that developers who use a relational database should know how to work with SQL. Active Record simplifies the common cases, but once you start getting to more complicated scenarios it expects you use SQL directly.

I don't see the leakiness of the O/R abstraction as a condemnation of these frameworks. The point of these frameworks is to improve productivity by making the easier to do common things. It allows a team to focus its effort on the few cases that really matter. The problem only comes when a team believes the abstraction is water-tight, and puts no effort into working with SQL. It's a common failing, but not a reason to abandon the real advantages of O/R frameworks when they are used correctly.

Long Running Requests

A common problem we've seen is applications that get into a tangle when they take on a task that takes some time to carry out. Done naively this can result in the web request handler going dark for a worryingly long time while it deals with the request.

This is a very common issue with any human interface, and has a common solution - handing off the task to a background process or thread. Anyone who has programmed with a rich-client GUI application will recognize doing something like this. People do get themselves into trouble, however, if this hand-off and communication is done badly.

The route I prefer, and fortunately it seems most ThoughtWorkers agree with, is to use an actor. In this model the web request handler takes any long-running task, wraps it in a command and puts it it onto a queue. The background actor then monitors the queue, taking commands off the queue and executing them, signaling the human-interaction actor when it's done with each one. The queue usually starts as a table in the database, and then may migrate to a real message queue system if required.

As with the leakiness of Active Record, I point this out not because it's a particular problem to Rails applications, we see this in all sorts of applications. It's worth pointing out because it seems too easy for many people using Rails to forget that this kind of thing happens, and thus they need to use this kind of pattern. We have found that Rails makes much of the repetitive part of web application easier and quicker to do - but the more involved stuff remains.

Deployment

Rails applications are easy to build, but sadly have been very awkward to deploy. The common scenario of using a pack of several mongrel web servers is at best rather fiddly to set up. This is something that has stuck out rather starkly due to the contrast with the smoothness of much of the rest of the ruby experience.

The current consensus is that Phusion Passenger makes this whole thing very much simpler and is now the recommended deployment approach with the MRI.

We've been also big fans of using JRuby for deployments. JRuby allows people to use the standard Java Web-App stack, which can make it much easier to deal with in many corporate settings. Mingle has also used this approach to make it easier to install for customers. Indeed the Mingle team does all its development with the MRI but deploys to JRuby. They do this because the faster startup time of the MRI makes it quicker to develop on. (JRuby requires a JVM start-up, which is noticeably hesitant.)

Controlling Gems

Ruby includes a package-management system, Ruby Gems, that makes it easy to install and upgrade third-party libraries. Rails also has plugins that carry out a similar task for rails. These are good tools, but it's easy for teams to get in a tangle if different machines are set up with different versions of different libraries.

There's a couple of ways to handle this. The first approach involves taking a copy of the source code for all third-party libraries and checking that into source control. This way a simple checkout will get you all the right version of all the libraries. A second approach is to use a script that downloads and activates the correct versions of all libraries. This script needs to be kept in source control.

Along similar lines, most teams also takes a copy of the Rails source itself. This allows them to apply patches to Rails directly to fix any bugs or other vital issues. These patches can then be sent to the core team. Using distributed version control systems, like git, have made this a good bit easier to manage. It's certainly much easier than our memories of having to decompile and patch Java application servers in the past.

Schedule Time for Updates

Ruby generally, and Rails in particular, moves quickly. There are frequent updates to the rails system, with features that we want to use. We've found that we need to ensure we schedule time for handling rails updates and include these in the planning process. They are more significant than for other platforms, but the good news is that there's a steady stream of new capabilities.

Developing on Windows

Ruby was born in the unix world, and most of the people who have flocked to the platform use forward slashes for directory paths. It is possible to run, deploy, and develop for ruby on a windows platform, but it's also much more tricky. Our general advice is to use a unix platform for all development. Macs are commonly preferred, but plenty of people use other FOSS Unixen too.

We hope this situation will change as Iron Ruby develops. It would be nice to have the option to deploy Ruby applications on the base Unix, JVM, or the CLR. Indeed this would make Ruby a particularly flexible option for runtime support across multiple platforms. It would also help our .NET projects to have Ruby as a scripting language in conjunction with the mainline .NET languages.



Acknowledgments

Even more than usual, I couldn't have put all this together without the collaboration of many of my colleagues. Although I've been using Ruby for much personal work for many years, there's a big difference between one man cobbing together his personal web site and the kinds of application that we do with our clients. I'm grateful that so many of my colleagues took time out to give me the information I needed to truly assess Ruby's value.

And like any users of Ruby, we owe thanks to the wider Ruby and Rails communities. With any open-source effort, the role of the community is vital, so to all Ruby-hackers and Rubyists we at ThoughtWorks say ありがとうございました

Wednesday, May 26, 2010

Learn Ruby on Rails: the Ultimate Beginner’s Tutorial

While it certainly makes no attempt to constitute a complete guide to the Ruby language, this tutorial will introduce you to some of the basics of Ruby. We'll power through a crash-course in object oriented programming, covering the more common features of the language along the way, and leaving the more obscure aspects of Ruby for a dedicated reference guide [1]. I'll also point out some of the advantages that Ruby has over other languages when it comes to developing applications for the Web.

Some Rails developers suggest that it's possible to learn and use Rails without learning the Ruby basics first, but as far as I'm concerned, it's extremely beneficial to know even a little Ruby before diving into the guts of Rails. In fact, if you take the time to learn the Ruby basics first, you'll automatically become a better Rails programmer.

That's what this tutorial is all about. In fact, this information is excerpted from my new book, Build Your Own Ruby On Rails Web Applications [2], which is now available through sitepoint.com. The two chapters presented here get straight into the finer points of Ruby and Rails. If you need installation and other setup instructions, download the sample PDF, which contains chapters 1 to 4 [3].

Ruby is a Scripting Language

In general, programming languages fall into one of two categories: they're either compiled languages or scripting languages. Let's explore what each of those terms means, and understand the differences between them.

Compiled Languages

The language in which you write an application is not actually something that your computer understands. Your code needs to be translated into bits and bytes that can be executed by your computer. This process of translation is called compilation, and any language that requires compilation is referred to as a compiled language. Examples of compiled languages include C, C#, and Java.

For a compiled language, the actual compilation is the final step in the development process. You invoke a compiler -- the software program that translates your final hand-written, human-readable code into machine-readable code -- and the compiler creates an executable file. This final product is then able to execute independently of the original source code.

Thus, if you make changes to your code, and you want those changes to be incorporated into the application, you must stop the running application, recompile it, then start the application again.

Scripting Languages

On the other hand, a scripting language such as Ruby, PHP, or Python, relies upon an application's source code all of the time. Scripting languages don't have a compiler or a compilation phase per se; instead, they use an interpreter -- a program that runs on the web server -- to translate hand-written code into machine-executable code on the fly. The link between the running application and your hand-crafted code is never severed, because that scripting code is translated every time it is invoked -- in other words, for every web page that your application renders.

As you might have gathered from the name, the use of an interpreter rather than a compiler is the major difference between a scripting language and a compiled language.

The Great Performance Debate

If you've come from a compiled-language background, you might be concerned by all this talk of translating code on the fly -- how does it affect the application's performance?

These concerns are valid -- translating code on the web server every time it's needed is certainly more expensive, performance-wise, than executing pre-compiled code, as it requires more effort on the part of your machine's processor. The good news is that there are ways to speed up scripted languages, including techniques such as code caching and persistent interpreters. However, both topics are beyond the scope of this book.

There's also an upside to scripted languages in terms of performance -- namely, your performance while developing an application.

Imagine that you've just compiled a shiny new Java application, and launched it for the first time ... and then you notice a typo on the welcome screen. To fix it, you have to stop your application, go back to the source code, fix the typo, wait for the code to recompile, and restart your application to confirm that it is fixed. And if you find another typo, you'll need to repeat that process again. Lather, rinse, repeat.

In a scripting language, you can fix the typo and just reload the page in your browser -- no restart, no recompile, no nothing. It's as simple as that.

Ruby is an Object Oriented Language

Ruby, from its very beginnings, was built as a programming language that adheres to the principles of object oriented programming (OOP). Before getting into Ruby specifics, I'd like to introduce you to some fundamental concepts of OOP. Now I know that theory can seem a bit dry to those who are itching to start coding, but we'll cover a lot of ground in this short section, so don't skip it. This discussion will hold you in good stead -- trust me.

OOP is a programming paradigm that first surfaced in the 1960s, but didn't gain traction until the 1980s with C++. The core idea behind it is that programs should be composed of individual entities, or objects, each of which has the ability to communicate with other objects around it. Additionally, each object may have the facility to store data internally, as depicted in Figure 3.1.

1562_fig1
Figure 3.1. Communication between objects

Objects in an OOP application are often modeled on real-world objects, so even non-programmers can usually recognize the basic role that an object plays.

And, just like the real world, OOP defines objects with similar characteristics as belonging to the same class. A class is a construct for defining properties for objects that are alike, and equipping them with functionality. For example, a class named Car might define the attributes color and mileage for its objects, and assign them functionality -- actions such as "open the trunk," "start the engine," and "change gears." These different actions are known as methods, although you'll often see Rails enthusiasts refer to the methods of a controller as "actions" -- you can safely consider the two terms to be interchangeable.

Understanding the relationship between a class and its objects is integral to understanding how OOP works. For instance, one object can invoke functionality on another object, and can do so without affecting other objects of the same class. So, if one car object was instructed to open its trunk (think of KITT, the talking car from the classic 80s television show "Knight Rider," if it helps with the metaphor), then its trunk would open, but the trunk of other cars would remain closed. Similarly, if our high-tech talking car were instructed to change color to red, then it would do so, but other cars would not. ("Knight Rider [4]" was a popular series in the 1980s that featured modern-day cowboy Michael Knight (played by David Hasselhoff) and his opinionated, talking, black Pontiac Firebird named KITT. Having seen the show is not critical to understanding object oriented programming?just knowing that the car could talk will suffice!)

When we create a new object in OOP, we base it on an existing class. The process of creating new objects from a class is called instantiation. Figure 3.2 illustrates the concept.

1562_fig2
Figure 3.2. Classes and objects

As I mentioned, objects can communicate with each other and invoke functionality (methods) on other objects. Invoking an object's methods can be thought of as asking the object a question, and getting an answer in return.

Consider the example of our famous talking car again. Let's say we ask the talking car object to report its current mileage. This question is not ambiguous -- the answer that the object gives is called a return value, and is shown in Figure 3.3.

1562_fig3
Figure 3.3. Asking a simple question

In some cases, the question and answer analogy doesn't quite fit. In these situations, we might rephrase the analogy to consider the question to be an instruction, and the answer a status report indicating whether or not the instruction was executed successfully. This might look something like the diagram in Figure 3.4.

1562_fig4
Figure 3.4. Sending instructions

Sometimes we need a bit more flexibility with our instructions. For example, if we wanted to tell our car to change gear, we need to tell it not only to change gear, but also which gear to change to. The process of asking these kinds of questions is referred to as passing an argument to the method.

An argument is an input value that's provided to a method. An argument can be used in two ways:

  • to influence how a method operates
  • to influence which object a method operates on

An example is shown in Figure 3.5, where the method is "change gear," and the number of the gear to which the car must change (two) is the argument.

1562_fig5
Figure 3.5. Passing arguments

A more general view of all of these different types of communication between objects is this: invoking an object's methods is accomplished by sending messages to it. As one might expect, the object sending the message is called the sender, and the object receiving the message is called the receiver.

Armed with this basic knowledge about object oriented programming, let's look at some Ruby specifics.

Reading and Writing Ruby Code

Learning the syntax of a new language has the potential to induce the occasional yawn. So, to make things more interesting, I'll present it to you in a practical way that lets you play along at home: we'll use the interactive Ruby shell.

The Interactive Ruby Shell (irb)

You can fire up the interactive Ruby shell by entering irb into a terminal window.

Not the Standard DOS Box!
Windows users, don't forget to use the Open Ruby Console option from the Instant Rails control panel, to make sure the environment you're using contains the right settings.

irb allows you to issue Ruby commands interactively, one line at a time. This is great for playing with the language, and it's also great for debugging, as we'll see in Chapter 11, Debugging, Testing, and Benchmarking.

A couple of points about the irb output you'll see in this chapter:

  • Lines beginning with the Ruby shell prompt (irb>) are typed in by you (and me).
  • Lines beginning with => show the return value of the command that has been entered.

We'll start with a really brief example:

irb> 1
=> 1

In this example, I've simply thrown the number 1 at the Ruby shell, and got back what appears to be the very same number.

Looks can be deceiving, though -- it's actually not the very same number. What we were handed back is in fact a fully-featured Ruby object.

Remember our discussion about object oriented programming in the previous section? Well, in Ruby, absolutely everything is treated as an object with which we can interact -- each object belongs to a certain class, therefore each object is able to store data and functionality in the form of methods.

To find the class to which our number belongs, we call the number's class method:

irb> 1.class
=> Fixnum

We touched on senders and receivers earlier. In this example, we've sent the class message to the 1 object, so the 1 object is the receiver (there's no sender, as we're sending the message from the interactive command line rather than from another object). The value that's returned by the method we've invoked is Fixnum, which is the Ruby class that represents integer values.

Since everything in Ruby (including a class) is an object, we can actually send the very same message to the Fixnum class. The result is different, as we'd expect:

irb> Fixnum.class
=> Class

This time, the return value is Class, which is somewhat reassuring -- we did invoke it on a class name, after all.

Note that the method class is all lowercase, yet the return value Class begins with a capital letter. A method in Ruby is always written in lowercase, whereas the first letter of a class is always capitalized.

Interacting with Ruby Objects

Getting used to thinking in terms of objects can take some time. Let's look at a few different types of objects, and see how we can interact with them.

Literal Objects

Literal objects are character strings or numbers that appear directly in the code, as did the number 1 that was returned in the previous section. We've seen numbers in action; next, let's look at a string literal.

A string literal is an object that contains a string of characters, such as a name, an address, or an especially witty phrase. In the same way that we created the 1 literal object in the previous example, we can easily create a new string literal object, then send it a message. A string literal is created by enclosing the characters that make up the string in single or double quotes, like this:

irb> "The quick brown fox"
=> "The quick brown fox"

First, we'll confirm that our string literal indeed belongs to class String:

irb> "The quick brown fox".class
=> String

This String object has a wealth of embedded functionality. For example, we can ascertain the number of characters that our string literal comprises by sending it the length message:

irb> "The quick brown fox".length
=> 19

Easy stuff, eh?

Variables and Constants

Every application needs a way to store information. Enter: variables and constants. As their names imply, these two data containers have their own unique roles to play.

A constant is an object that's assigned a value once, and once only (usually when the application starts up). Constants are therefore used to store information that doesn't need to change within a running application. As an example, a constant might be used to store the version number for an application. Constants in Ruby are always written using uppercase letters, as shown below:

irb> CONSTANT = "The quick brown fox in a constant"
=> "The quick brown fox in a constant"
irb> APP_VERSION = 5.04
=> 5.04

Variables, in contrast, are objects that are able to change at any time. They can even be reset to nothing, which frees up the memory space that they previously occupied. Variables in Ruby always start with a lowercase character:

irb> variable = "The quick brown fox in a variable"
=> "The quick brown fox in a variable"

There's one more special (and, one might say, evil) thing about a variable -- its scope. The scope of a variable is the part of the program to which a variable is visible. If you try to access a variable from outside its scope (i.e. from a part of an application to which that variable is not visible), you generally won't be able to.

The notable exception to the rules defining a variable's scope are global variables. As the name implies, a global variable is accessible from any part of the program. While this might sound convenient at first, usage of global variables is discouraged -- the fact that they can be written to and read from any part of the program introduces security concerns.

Let's return to the string literal example we saw earlier. Assigning a String to a variable allows us to invoke on that variable the same methods we invoked on the string literal earlier:

irb> fox = "The quick brown fox"
=> "The quick brown fox"
irb> fox.class
=> String
irb> fox.length
=> 19

Punctuation in Ruby

The use of punctuation in Ruby code differs greatly from other languages such as Perl and PHP, so it can seem confusing at first if you're used to programming in those languages. However, once you have a few basics under your belt, punctuation in Ruby begins to feel quite intuitive and can greatly enhance the readability of your code.

Dot Notation

One of the most common punctuation characters in Ruby is the period (.). As we've seen, Ruby uses the period to separate the receiver from the message that's being sent to it, in the form Object.receiver.

If you need to comment a line, either for documentation purposes or to temporarily take a line of code out of the program flow, use a hash mark (#). Comments may start at the beginning of a line, or they may appear further along, after some Ruby code:

irb> # This is a comment. It doesn't actually do anything.
irb> 1 # So is this, but this one comes after a statement.
=> 1
irb> fox = "The quick brown fox" # Assign to a variable
=> "The quick brown fox"
irb> fox.class # Display a variable's class
=> String
irb> fox.length # Display a variable's length
=> 19

Chaining Statements Together

Ruby doesn't require us to use any character to separate commands, unless we want to chain multiple statements together on a single line. In this case, a semicolon (;) is used as the separator. However, if you put every statement on its own line (as we've been doing until now), the semicolon is completely optional.

If you chain multiple statements together in the interactive shell, only the output of the last command that was executed will be displayed to the screen:

irb> fox.class; fox.length; fox.upcase
=> "THE QUICK BROWN FOX"

Use of Parentheses

If you've ever delved into the source code of one of the many JavaScript libraries out there, you might have run screaming from your computer when you saw all the parentheses that are involved in the passing of arguments to methods [5].

In Ruby, the use of parentheses for method calls is optional in cases in which no arguments are passed to the method. The following statements are therefore equal:

irb> fox.class()
=> String
irb> fox.class
=> String

It's common practice to include parentheses for method calls with multiple arguments, such as the insert method of the String class:

irb> "jumps over the lazy dog".insert(0, 'The quick brown fox ')
=> "The quick brown fox jumps over the lazy dog"

This call inserts the second argument passed to the insert object ("The quick brown fox ") at position 0 of the receiving String object ("jumps over the lazy dog"). Position 0 refers to the very beginning of the string.

Method Notation

Until now, we've looked at cases where Ruby uses less punctuation than its competitors. In fact, Ruby makes heavy use of expressive punctuation when it comes to the naming of methods.

A regular method name, as we've seen, is a simple, alphanumeric string of characters. If a method has a potentially destructive nature (for example, it directly modifies the receiving object rather than changing a copy of it), it's commonly suffixed with an exclamation mark (!).

The following example uses the upcase method to illustrate this point:

irb> fox.upcase
=> "THE QUICK BROWN FOX"
irb> fox
=> "The quick brown fox"
irb> fox.upcase!
=> "THE QUICK BROWN FOX"
irb> fox
=> "THE QUICK BROWN FOX"

Here, the contents of the fox variable have been modified by the upcase! method.

Punctuation is also used in the names of methods that return boolean values. A boolean value is a value that's either true or false; these values are commonly used as return values for methods that ask yes/no questions. Such methods end in a question mark, which nicely reflects the fact that they have yes/no answers:

irb> fox.empty?
=> false
irb> fox.is_a? String
=> true

These naming conventions make it easy to recognize methods that are destructive, and those that return boolean values, making your Ruby code more readable.

Object Oriented Programming in Ruby

Let's build on the theory that we covered at the start of this chapter as we take a look at Ruby's implementation of OOP.

As we already know, the structure of an application based on OOP principles is focused on interaction with objects. These objects are often representations of real-world objects, like a Car. Interaction with an object occurs when we send it a message or ask it a question. If we really did have a Car object called kitt (we don't -- yet), starting the car might be as simple as:

irb> kitt.start

This short line of Ruby code sends the message start to the object kitt. Using OOP terminology, we would say that this code statement calls the start method of thekitt object.

As I mentioned before, in contrast to other object oriented programming languages such as Python and PHP, in Ruby, everything is an object. Especially when compared with PHP, Ruby's OOP doesn't feel like a "tacked-on" afterthought -- it was clearly intended to be a core feature of the language from the beginning, which makes using the OOP features in Ruby a real pleasure.

As we saw in the previous section, even the simplest of elements in Ruby (like literal strings and numbers) are objects to which you can send messages.

Classes and Objects

As in any other OOP language, in Ruby, each object belongs to a certain class (for example, PontiacFirebird might be an object of class Car). As we saw in the discussion at the beginning of this chapter, a class can group objects of a certain kind, and equip those objects with common functionality. This functionality comes in the form of methods, and in the object's ability to store information. For example, a PontiacFirebird object might need to store its mileage, as might any other object of the class Car.

In Ruby, the instantiation of a new object that's based on an existing class is accomplished by sending that class the new message. The result is a new object of that class. The following few lines of code show an extremely basic class definition into Ruby -- the third line is where we create an instance of the class that we just defined.

irb> class Car
irb> end
=> nil
irb> kitt = Car.new
=> #

Another basic principle in OOP is encapsulation. According to this principle, objects should be treated as independent entities, each taking care of its own internal data and functionality. If we need to access an object's information -- for instance, its internal variables -- we make use of the object's interface, which is the subset of the object's methods that are made available for other objects to call.

Ruby provides objects with functionality at two levels -- the object level, and class level -- and it adheres to the principle of encapsulation while it's at it! Let's dig deeper.

Object-level Functionality

At the object level, data storage is handled by instance variables (a name that's derived from the instantiation process mentioned above). Think of instance variables as storage containers that are attached to the object, but to which other objects do not have direct access.

To store or retrieve data from these variables, another object must call an accessor method on the object. An accessor method has the ability to set (and get) the value of the object's instance variables.

Let's look at how instance variables and accessor methods relate to each other, and how they're implemented in Ruby.

Instance Variables

Instance variables are bound to an object, and contain values for that object only.

Revisiting our cars example, the mileage values for a number of different Car objects are likely to differ, as each car will have a different mileage. Therefore, mileage is held in an instance variable.

An instance variable can be recognized by its prefix: a single "at" sign (@). And what's more, instance variables don't even need to be declared! There's only one problem: we don't have any way to retrieve or change them once they do exist. This is where instance methods come into play.

Instance Methods

Data storage and retrieval is not the only capability that can be bound to a specific object -- functionality, too, can be bound to objects. We achieve this binding through the use of instance methods, which are specific to an object. Invoking an instance method (in other words, sending a message that contains the method name to an object) will invoke that functionality on the receiving object only.

Instance methods are defined using the def keyword, and end with the end keyword. Enter the following example into a new Ruby shell:

$ irb
irb> class Car
irb> def open_trunk
irb> # code to open trunk goes here
irb> end
irb> end
=> nil
irb> kitt = Car.new
=> #

What you've done is define a class called Car, which has an instance method with the name open_trunk. A Car object instantiated from this class will (possibly using some fancy robotics connected to our Ruby program) open its trunk when its open_trunk method is called. (Ignore that nil return value for the moment; we'll look at nil values in the next section.)

Indenting your Code
While the indentation of code is a key element of the syntax of languages such as Python, in Ruby, indentation is purely cosmetic -- it aids readability, but does not affect the code in any way. In fact, while we're experimenting with the Ruby shell, you needn't be too worried about indenting any of the code. However, when we're saving files that will be edited later, you'll want the readability benefits that come from indenting nested lines.

The Ruby community has agreed upon two spaces as being optimum for indenting blocks of code such as class or method definitions. We'll adhere to this indentation scheme throughout this book.

With our class in place, we can make use of this method:

irb> kitt.open_trunk
=> nil

Since we don't want the trunks of all cars to open at once, we've made this functionality available as an instance method.

I know, I know: we still haven't modified any data. We use accessor methods for this task.

Accessor Methods

An accessor method is a special type of instance method, and is used to read or write to an instance variable. There are two types: readers (sometimes called "getters") and writers (or "setters").

A reader method will look inside the object, fetch the value of an instance variable, and hand this value back to us. A writer method, on the other hand, will look inside the object, find an instance variable, and assign the variable the value that it was passed.

Let's add some methods for getting and setting the @mileage attribute of our Car objects. Once again, exit from the Ruby shell so that we can create an entirely new Carclass definition. Our class definition is getting a bit longer now, so enter each line carefully. If you make a typing mistake, exit the shell and start over.

$ irb
irb> class Car
irb> def set_mileage(x)
irb> @mileage = x
irb> end
irb> def get_mileage
irb> @mileage
irb> end
irb> end
=> nil
irb> kitt = Car.new
=> #

Now, we can finally modify and retrieve the mileage of our Car objects!

irb> kitt.set_mileage(5667)
=> 5667
irb> kitt.get_mileage
=> 5667

This is still a bit awkward. Wouldn't it be nice if we could give our accessor methods exactly the same names as the attributes that they read from or write to? Luckily, Ruby contains shorthand notation for this very task. We can rewrite our class definition as follows:

$ irb
irb> class Car
irb> def mileage=(x)
irb> @mileage = x
irb> end
irb> def mileage
irb> @mileage
irb> end
irb> end
=> nil
irb> kitt = Car.new
=> #

With these accessor methods in place, we can read to and write from our instance variable as if it were available from outside the object.

irb> kitt.mileage = 6032
=> 6032
irb> kitt.mileage
=> 6032

These accessor methods form part of the object's interface.

Class-level Functionality

At the class level, class variables handle data storage. They're commonly used to store state information, or as a means of configuring default values for new objects. Class variables are typically set in the body of a class, and can be recognized by their prefix: a double "at" sign (@@).

First, enter the following class definition into a new Ruby shell.

$ irb
irb> class Car
irb> @@number_of_cars = 0
irb> def initialize
irb> @@number_of_cars = @@number_of_cars + 1
irb> end
irb> end
=> nil

The class definition for the class Car above has an internal counter for the total number of Car objects that have been created. Using the special instance methodinitialize, which is invoked automatically every time an object is instantiated, this counter is incremented for each new Car object.

By the way, we have actually already used a class method. Do you like how I snuck it in there? The new method is an example of a class method that ships with Ruby and is available to all classes -- whether they're defined by you, or form part of the Ruby Standard Library. (The Ruby Standard Library is a large collection of classes that's included with every Ruby installation. The classes facilitate a wide range of common functionality, such as accessing web sites, date calculations, file operations, and more.)

Custom class methods are commonly used to create objects with special properties (such as a default color for our Car objects), or to gather statistics about the class's usage.

Extending the earlier example, we could use a class method called count to return the value of the @@number_of_cars class variable. Remember that this is a variable that's incremented for every new Car object that's created. Class methods are defined identically to instance methods: using the def and end keywords. The only difference is that class method names are prefixed with self. Enter this code into a new Ruby shell:

$ irb
irb> class Car
irb> @@number_of_cars = 0
irb> def self.count
irb> @@number_of_cars
irb> end
irb> def initialize
irb> @@number_of_cars+=1
irb> end
irb> end
=> nil

The following code instantiates some new Car objects, then makes use of our new class method:

irb> kitt = Car.new # Michael Knight's talking car
=> #<0xba8c>
irb> herbie = Car.new # The famous VolksWagen love bug!
=> #<0x8cd20>
irb> batmobile = Car.new # Batman's sleek automobile
=> #<0x872e4>
irb> Car.count
=> 3

The method tells us that three instances of the Car class have been created. Note that we can't call a class method on an object (Ruby actually does provide a way to invoke some class methods on an object, using the :: operator, but we won't worry about that for now. We'll see the :: operator in use in Chapter 4, Rails Revealed.):

irb> kitt.count
NoMethodError: undefined method 'count' for #

As implied by the name, the count class method is available only to the Car class, not to any objects instantiated from that class.

I sneakily introduced something else in there. Did you spot it? In many languages, including PHP and Java, the ++ and -- operators are used to increment a variable by one. Ruby doesn't support this notation; instead, when working with Ruby, we need to use the += operator. Therefore, the shorthand notation for incrementing our counter in the class definition is:

irb> @@number_of_cars+=1

This code is identical to the following:

irb> @@number_of_cars = @@number of cars + 1

Both of these lines can be read as "my_variable becomes equal to my_variable plus one."

Inheritance

If your application deals with more than the flat hierarchy we've explored so far, you might want to construct a scenario whereby some classes inherit from other classes. Continuing with the car analogy, let's suppose that we had a green limousine named Larry (this assigning of names to cars might feel a bit strange, but it's important for this example, so bear with me). In Ruby, the larry object would probably descend from a StretchLimo class, which could in turn descend from the class Car. Let's implement that, to see how it works:

$ irb
irb> class Car
irb> @@wheels = 4
irb> end
=> nil
irb> class StretchLimo < class="Apple-converted-space">
irb> @@wheels = 6
irb> def turn_on_television
irb> # Invoke code for switching on on-board TV here
irb> end
irb> end
=> nil

Now, if we were to instantiate an object of class StretchLimo, we'd end up with a different kind of car. Instead of the regular four wheels that standard Car objects have, this one would have six wheels (stored in the class variable @@wheels). It would also have extra functionality, made possible by an extra method --turn_on_television -- which would be available to be called by other objects.

However, if we were to instantiate a regular Car object, the car would have only four wheels, and there would be no instance method for turning on an on-board television. Think of inheritance as a way for the functionality of a class to become more specialized the further we move down the inheritance path.

Don't worry if you're struggling to wrap your head around all the aspects of OOP -- you'll automatically become accustomed to them as you work through this book. You might find it useful to come back to this section, though, especially if you need a reminder about a certain term later on.

Return Values

It's always great to receive feedback. Remember our talk about passing arguments to methods? Well, regardless of whether or not a method accepts arguments, invoking a method in Ruby always results in feedback -- it comes in the form of a return value, which is returned either explicitly or implicitly.

To return a value explicitly, use the return statement in the body of a method:

irb> def toot_horn
irb> return "toooot!"
irb> end
=> nil

Calling the toot_horn method in this case would produce the following:

irb> toot_horn
=> "toooot!"

However, if no return statement is used, the result of the last statement that was executed is used as the return value. This behavior is quite unique to Ruby:

irb> def toot_loud_horn
irb> "toooot!".upcase
irb> end
=> nil

Calling the toot_loud_horn method in this case would produce:

irb> toot_loud_horn
=> "TOOOOT!"

Standard Output

When you need to show output to the users of your application, use the print and puts ("put string") statements. Both methods will display the arguments passed to them as Strings; puts also inserts a carriage return at the end of its output. Therefore, in a Ruby program the following lines:

print "The quick "
print "brown fox"

would produce this output:

The quick brown fox

However, using puts like so:

puts "jumps over"
puts "the lazy dog"

would produce this output:

jumps over
the lazy dog

At this stage, you might be wondering why all of the trial-and-error code snippets that we've typed into the Ruby shell actually produced output, given that we haven't been making use of the print or puts methods. The reason is that irb automatically writes the return value of the last statement it executes to the screen before displaying the irb prompt. This means that using a print or puts from within the Ruby shell might in fact produce two lines of output -- the output that you specify should be displayed, and the return value of the last command that was executed, as in the following example:

irb> puts "The quick brown fox"
"The quick brown fox"
=> nil

Here, nil is actually the return value of the puts statement. Looking back at previous examples, you will have encountered nil as the return value for class and method definitions, and you'll have received a hexadecimal address, such as <#Car:0x89da0>, as the return value for object definitions. This hexadecimal value showed the location in memory that the object we instantiated occupied, but luckily we won't need to bother with such geeky details any further.

Having met the print and puts statements, you should be aware that a Rails application actually has a completely different approach to displaying output, called templates. We'll look at templates in Chapter 4, Rails Revealed.

Ruby Core Classes

We've already talked briefly about the String and Fixnum classes in the previous sections, but Ruby has a lot more under its hood. Let's explore!

Arrays

We use Ruby's Arrays to store collections of objects. Each individual object that's stored in an Array has a unique numeric key, which we can use to reference it. As with many languages, the first element in an Array is stored at position 0 (zero).

To create a new Array, simply instantiate a new object of class Array (using the Array.new construct). You can also use a shortcut approach, which is to enclose the objects you want to place inside the Array in square brackets.

For example, an Array containing the mileage at which a car is due for its regular service might look something like this:

irb> service_mileage = [5000, 15000, 30000, 60000, 100000]
=> [5000, 15000, 30000, 60000, 100000]

To retrieve individual elements from an Array, we specify the numeric key in square brackets.

irb> service_mileage[0]
=> 5000
irb> service_mileage[2]
=> 30000

Ruby has another shortcut, which allows us to create an Array from a list of Strings: the %w( ) syntax. Using this shortcut saves us from having to type a lot of double-quote characters:

irb> available_colors = %w( red green blue black )
=> ["red", "green", "blue", "black"]
irb> available_colors[0]
=> "red"
irb> available_colors[3]
=> "black"

In addition to facilitating simple element retrieval, Arrays come with an extensive set of class methods and instance methods that ease data management tasks tremendously.

empty? returns true if the receiving Array doesn't contain any elements:

irb> available_colors.empty?
=> false

size returns the number of elements in an Array:

irb> available_colors.size
=> 4

first and last return an Array's first and last elements, respectively:

irb> available_colors.first
=> "red"
irb> available_colors.last
=> "black"

delete removes the named element from the Array and returns it:

irb> available_colors.delete "red"
=> "red"
irb> available_colors
=> ["green", "blue", "black"]

The complete list of class methods and instance methods provided by the Array class is available via the Ruby reference documentation, which you can access by entering the ri command into the terminal window (for your operating system, not the Ruby shell), followed by the class name you'd like to look up:

$ ri Array

Oh, and ri stands for ruby interactive, in case you're wondering. Don't confuse it with irb.

Hashes

A Hash is another kind of data storage container. Hashes are similar, conceptually, to dictionaries: they map one object (the key -- for example, a word) to another object (the value -- for example, a word's definition) in a one-to-one relationship.

New Hashes can be created either by instantiating a new object of class Hash (using the Hash.new construct) or by using the curly brace shortcut shown below. When we define a Hash, we must specify each entry using the key => value syntax.

For example, the following Hash maps car names to a color:

irb> car_colors = {
irb> 'kitt' => 'black',
irb> 'herbie' => 'white',
irb> 'batmobile' => 'black',
irb> 'larry' => 'green'
irb> }
=> {"kitt"=>"black", "herbie"=>"white", "batmobile"=>"black",
"larry"=>"green"}

To query this newly built Hash, we pass the key of the entry we want to look up in square brackets, like so:

irb> car_colors['kitt']
=> "black"

All sorts of useful functionality is built into Hashes, including the following methods:

empty? returns true if the receiving Hash doesn't contain any elements:

irb> car_colors.empty?
=> false

size returns the number of elements in a Hash:

irb> car_colors.size
=> 4

keys returns all keys of a Hash as an Array:

irb> car_colors.keys
=> ["kitt", "herbie", "larry", "batmobile"]

values returns all values of a Hash as an Array, although care should be taken with regards to the order of the elements (keys in a Hash are ordered for optimal storage and retrieval; this order does not necessarily reflect the order in which they were entered):

irb> car_colors.values
=> ["black", "white", "green", "black"]

There are lots more -- for the complete list of class methods and instance methods provided by the Hash class, consult the Ruby reference documentation.

Strings

The typical Ruby String object -- yep, that very object we've been using in the past few sections -- holds and manipulates sequences of characters. Most of the time, newString objects are created using string literals that are enclosed in single or double quotes. The literal can then be stored in a variable for later use:

irb> a_phrase = "The quick brown fox"
=> "The quick brown fox"
irb> a_phrase.class
=> String

If the string literal includes the quote character used to enclose the string itself, it must be escaped with a backslash character (\):

irb> 'I\'m a quick brown fox'
=> "I'm a quick brown fox"
irb> "Arnie said, \"I'm back!\""
=> "Arnie said, \"I'm back!\""

An easier way to specify string literals that contain quotes is to use the %Q shortcut, like this:

irb> %Q(Arnie said, "I'm back!")
=> "Arnie said, \"I'm back!\""

String objects also support the substitution of Ruby code into a string literal via the Ruby expression #{}:

irb> "The current time is: #{Time.now}"
=> "The current time is: Wed Aug 02 21:15:19 CEST 2006"

The String class also has rich embedded functionality for modifying String objects. Here are some of the most useful methods:

gsub substitutes a given pattern within a String:

irb> "The quick brown fox".gsub('fox', 'dog')
=> "The quick brown dog"

include? returns true if a String contains another specific String:

irb> "The quick brown fox".include?('fox')
=> true

length returns the length of a String in characters:

irb> "The quick brown fox".length
=> 19

slice returns a portion of a String:

irb> "The quick brown fox".slice(0, 3)
=> "The"

The complete method reference is available using the ri command-line tool:

$ ri String

Numerics

Since there are so many different types of numbers, Ruby has a separate class for each, the popular Float, Fixnum, and Bignum classes among them. In fact, they're all subclasses of Numeric, which provides the basic functionality.

Just like Strings, numbers are usually created from literals:

irb> 123.class
=> Fixnum
irb> 12.5.class
=> Float

Each of the specific Numeric subclasses comes with features that are relevant to the type of number it's designed to deal with. However, the following functionality is shared between all Numeric subclasses:

integer? returns true if the object is a whole integer:

irb> 123.integer?
=> true
irb> 12.5.integer?
=> false

round rounds a number to the nearest integer:

irb> 12.3.round
=> 12
irb> 38.8.round
=> 39

zero? returns true if the number is equal to zero:

irb> 0.zero?
=> true
irb> 8.zero?
=> false

Additionally, there are ways to convert numbers between the Numeric subclasses. to_f converts a value to a Float, and to_i converts a value to an Integer:

irb> 12.to_f
=> 12.0
irb> 11.3.to_i
=> 11

Symbols

In Ruby, a Symbol is a simple textual identifier. Like a String, a Symbol is created using literals; the difference is that a Symbol is prefixed with a colon:

irb> :fox
=> :fox
irb> :fox.class
=> Symbol

The main benefit of using a Symbol instead of a String is that a Symbol contains less functionality. This can be an advantage in certain situations. For example, thecar_colors Hash that we looked at earlier could be rewritten as follows:

car_colors =
:kitt => 'black',
:herbie => 'white',
:larry => 'green',
:batmobile => 'black'
}

Objects of class String can be converted to Symbols, and vice-versa:

irb> "fox".to_sym
=> :fox
irb> :fox.to_s
=> "fox"

We'll use Symbols frequently as we deal with Rails functionality in successive chapters of this book.

nil

I promised earlier that I'd explain nil values -- now's the time!

All programming languages have a value that they can use when they actually mean nothing. Some use undef; others use NULL. Ruby uses nil. A nil value, like everything in Ruby, is also an object. It therefore has its own class: NilClass.

Basically, if a method doesn't return anything, it is, in fact, returning the value nil. And if you assign nil to a variable, you effectively make it empty. nil shows up in a couple of additional places, but we'll cross those bridges when we come to them.

Running Ruby Files

For the simple Ruby basics that we've experimented with so far, the interactive Ruby shell (irb) has been our tool of choice. I'm sure you'll agree that experimenting in a shell-like environment, where we can see immediate results, is a great way to learn the language.

However, we're going to be talking about control structures next, and for tasks of such complexity, you'll want to work in a text editor. This environment will allow you to run a chunk of code many times without having to retype it.

In general, Ruby scripts are simple text files containing Ruby code and have a .rb extension. These files are passed to the Ruby interpreter, which executes your code, like this:

$ ruby myscript.rb

To work with the examples that follow, I'd recommend that you open a new text file in your favorite text editor (which might be one of those I recommended back in Chapter 2, Getting Started) and type the code out as you go -- this really is the best way to learn. However, I acknowledge that some people aren't interested in typing everything out, and just want to cut to the chase. These more impatient readers can download the code archive for this book, which contains all of these examples. You can execute this code in the Ruby interpreter straight away.

As demonstrated above, to run the files from the command line, you simply need to type ruby, followed by the filename.

Control Structures

Ruby has a rich set of features for controlling the flow of your application. Conditionals are key words that are used to decide whether or not certain statements are executed based on the evaluation of one or more conditions; loops are constructs that execute statements more than once; blocks are a means of encapsulating functionality (for example, to be executed in a loop).

To demonstrate these control structures, let's utilize some of the Car classes that we defined earlier. Type out the following class definition and save the file (or load it from the code archive); we'll build on it in this section as we explore some control structures.

Example 3.1. 01-car-classes.rb

class Car
@@wheels = 4 # class variable
@@number_of_cars = 0 # class variable
def initialize
@@number_of_cars = @@number_of_cars + 1
end
def self.count
@@number_of_cars
end
def mileage=(x) # mileage writer
@mileage = x
end
def mileage # mileage reader
@mileage
end
end

class StretchLimo < class="Apple-converted-space">
@@wheels = 6 # class variable
@@televisions = 1 # class variable
def turn_on_television
# Invoke code for switching on on-board TV here
end
end

class PontiacFirebird < class="Apple-converted-space">
end

class VolksWagen < class="Apple-converted-space">
end

Conditionals

There are two basic conditional constructs in Ruby: if and unless. Each of these constructs can be used to execute a group of statements on the basis of a given condition.

The if Construct

An if construct wraps statements that are to be executed only if a certain condition is met. The keyword end defines the end of the if construct. The statements contained between the condition and the end keyword are executed only if the condition is met.

Example 3.2. 02-if-construct.rb (excerpt)

if Car.count.zero?
puts "No cars have been produced yet."
end

You can provide a second condition by adding an else block: when the condition is met, the first block is executed; otherwise, the else block is executed. This kind of control flow will probably be familiar to you. Here it is in action:

Example 3.3. 03-if-else-construct.rb (excerpt)

if Car.count.zero?
puts "No cars have been produced yet."
else
puts "New cars can still be produced."
end

The most complicated example involves an alternative condition. If the first condition is not met, then a second condition is evaluated. If neither conditions are met, theelse block is executed:

Example 3.4. 04-if-elsif-else.rb (excerpt)

if Car.count.zero?
puts "No cars have been produced yet."
elsif Car.count >= 10
puts "Production capacity has been reached."
else
puts "New cars can still be produced."
end

If the count method returned 5, the code above would produce the following output:

New cars can still be produced.

An alternative to the traditional if condition is the if statement modifier. A statement modifier does just that -- it modifies the statement of which it is part. The ifstatement modifier works exactly like a regular if condition, but it sits at the end of the line that's affected, rather than before a block of code:

Example 3.5. 05-if-statement-modifier.rb (excerpt)

puts "No cars have been produced yet." if Car.count.zero?

This version of the if condition is often used when the code that's to be executed conditionally comprises just a single line. Having the ability to create conditions like this results in code that's a lot more like English than other programming languages with more rigid structures.

The unless Construct

The unless condition is a negative version of the if condition. It's useful for situations in which you want to execute a group of statements when a certain condition is not met.

Let's create a few instances to work with (Aficionados of comics will notice that I've created the BatMobile as a Pontiac Firebird -- in fact, the caped crusader's choice of transport has varied over the years, taking in many of the automobile industry's less common innovations, and including everything from a 1966 Lincoln Futura to an amphibious tank. But we'll stick with a Pontiac for this example.):

Example 3.6. 06-unless-construct.rb (excerpt)

kitt = PontiacFirebird.new
kitt.mileage = 5667

herbie = VolksWagen.new
herbie.mileage = 33014

batmobile = PontiacFirebird.new
batmobile.mileage = 4623

larry = StretchLimo.new
larry.mileage = 20140

Now if we wanted to find out how many Knight Rider fans KITT could take for a joy-ride, we could check which class the kitt object was. As with the if expression, theend keyword defines the end of the statement.

Example 3.7. 06-unless-construct.rb (excerpt)

unless kitt.is_a?(StretchLimo)
puts "This car is only licensed to seat two people."
end

Like the if condition, the unless condition may have an optional else block of statements, which is executed when the condition is met:

Example 3.8. 07-unless-else.rb (excerpt)

unless kitt.is_a?(StretchLimo)
puts "This car only has room for two people."
else
puts "This car is licensed to carry up to 10 passengers."
end

Since KITT is definitely not a stretch limousine, this code would return:

This car only has room for two people.

Unlike if conditions, unless conditions do not support a second condition. However, like the if condition, the unless condition is also available as a statement modifier. The following code shows an example of this. Here, the message will not display if KITT's mileage is less than 25000:

Example 3.9. 08-unless-statement-modifier.rb (excerpt)

puts "Service due!" unless kitt.mileage <>

Loops

Ruby provides the while and for constructs for looping through code (i.e. executing a group of statements a specified number of times, or until a certain condition is met). Also, a number of instance methods are available for looping over the elements of an Array or Hash; we'll cover these in the next section.

while and until Loops

A while loop executes the statements it encloses repeatedly, as long as the specified condition is met.

Example 3.10. 09-while-loop.rb (excerpt)

while Car.count < class="Apple-converted-space">
Car.new
puts "A new car instance was created."
end

This simple while loop executes the Car.new statement repeatedly, as long as the total number of cars is below ten. It exits the loop when the number reaches ten.

Like the relationship between if and unless, the while loop also has a complement: the until construct. If we use until, the code within the loop is executed until the condition is met. We could rewrite the loop above using until like so:

Example 3.11. 10-until-loop.rb (excerpt)

until Car.count == 10
Car.new
puts "A new car instance was created."
end

The Difference Between = and ==
It's important to note the difference between the assignment operator (a single equal sign) and the equation operator (a double equal sign) when using them within a condition.

If you're comparing two values, use the equation operator:

if Car.count == 10
...
end

If you're assigning a value to a variable, use the assignment operator:

my_new_car = Car.new

If you confuse the two, you might modify a value that you were hoping only to inspect, with potentially disastrous consequences!

for Loops

for loops allow us to iterate over the elements of a collection -- such as an Array -- and execute a group of statements once for each element. Here's an example:

Example 3.12. 11-for-loop.rb (excerpt)

for car in [ kitt, herbie, batmobile, larry ]
puts car.mileage
end

The code above would produce the following output:

5667
33014
4623
20140

This simple for loop iterates over an Array of Car objects and outputs the mileage for each car. For each iteration, the car variable is set to the current element of theArray. The first iteration has car set to the equivalent of lincoln_towncar, the second iteration has it set to chrysler_voyager, and so forth.

In practice, the traditional while and for loops covered here are little used. Instead, most people tend to use the instance methods provided by the Array and Hashclasses, which we'll cover next.

Blocks

Blocks are probably the single most attractive feature of Ruby. However, they're also one of those things that take a while to "click" for Ruby newcomers. Before we dig deeper into creating blocks, let's take a look at some of the core features of Ruby that use blocks.

We looked at some loop constructs in the previous section, and this was a useful way to explore the tools that are available to us. However, you'll probably never actually come across many of these constructs in your work with other Ruby scripts, simply because it's almost always much easier to use a block to perform the same task. A block, in conjunction with the each method that is provided by the Array and Hash classes, is a very powerful way to loop through your data.

Let me illustrate this point with an example. Consider the for loop we used a moment ago. We could rewrite that code to use the each method, which is an instance method of the Array class, like so:

Example 3.13. 12-simple-block.rb (excerpt)

[ kitt, herbie, batmobile, larry ].each do |car_name|
puts car_name.mileage
end

Let's analyze this: the block comprises the code between the do and end keywords. A block is able to receive parameters, which are placed between vertical bars (|) at the beginning of the block. Multiple parameters are separated by commas. Therefore, this code performs an identical operation to the for loop we saw before, but in a much more succinct manner.

Let's take another example. To loop through the elements of a Hash, we use the each method, and pass two parameters to the block -- the key (car_name) and thevalue (color) -- like this:

Example 3.14. 13-block-with-params.rb (excerpt)

car_colors = {
'kitt' => 'black',
'herbie' => 'white',
'batmobile' => 'black',
'larry' => 'green'
}
car_colors.each do |car_name, color|
puts "#{car_name} is #{color}"
end

This code produces the following output:

kitt is black
herbie is white
batmobile is black
larry is green

The Integer class also sports a number of methods that use blocks. The times method of an Integer object, for example, executes a block exactly n times, where n is the value of the object.

Example 3.15. 14-block-integer.rb (excerpt)

10.times { Car.new }
puts "#{Car.count} cars have been produced."

The code above produces this output:

10 cars have been produced.

One final point to note here is the alternate block syntax of curly braces. Instead of the do...end keywords that we used in previous examples, curly braces are the preferred syntax for blocks that are very short, as in the previous example.

Here's another method of the Integer class -- in the spirit of times, the upto method counts from the value of the object up to the argument passed to the method.

Example 3.16. 15-block-upto.rb

5.upto(7) { |i| puts i }

This code produces the output shown here:

5
6
7

In Ruby parlance, the object i is a parameter of the block. Parameters for blocks are enclosed in vertical bars, and are usually available only from within the block. If we have more than one parameter, we separate them using commas, like so: |parameter1, parameter2|. In the example above, we would no longer have access to ionce the block had finished executing.

As we work through this book, we'll explore many more uses of blocks in combination with the Rails core classes.

Summary

Wow, we covered a lot in this chapter! First, we swept through a stack of object oriented programming theory -- probably the equivalent of an introductory computer science course! This gave us a good grounding for exploring the basics of the Ruby programming language, and the Interactive Ruby Shell (irb) was a fun way to do this exploration.

We also investigated many of the Ruby core classes, such as String, Array, and Hash, from within the Ruby shell. We then moved from the shell to create and save proper Ruby files, and using these files, we experimented with control structures such as conditionals, loops, and blocks.

In the next chapter, we'll look at the major cornerstones that make up the Rails framework -- the integrated testing facilities -- as well as the roles that the development, testing, and production environments play.

Chapter 4, Rails Revealed

As you might have gathered from Chapter 1, Introducing Ruby on Rails, quite a bit of thought has been put into the code base that makes up the Rails framework. Over time, many of the internals have been rewritten, which has improved their speed and efficiency, and allowed the implementation of additional features, but the original architecture remains largely unchanged. This chapter will shed some light on the inner workings of Rails.

Three Environments

Rails encourages the use of a different environment for each of the stages in an application's lifecycle -- development, testing, and production. If you've been developing Web applications for a while, this is probably how you operate anyway; Rails just formalizes these environments.

Development

In the development environment, changes to an application's source code are immediately visible; all we need to do is reload the corresponding page in a web browser. Speed is not a critical factor in this environment; instead, the focus is on providing the developer with as much insight as possible into the components involved in displaying each page. When an error occurs in the development environment, the developer is able to tell at a glance which line of code is responsible for the error, and how that particular line was invoked. This capability is provided by the stack trace (a comprehensive list of all the method calls leading up to the error), which is displayed when an unexpected error occurs.

Test

In testing, we usually refresh the database with a baseline of dummy data each time a test is repeated -- this ensures that the results of the tests are consistent, and that behavior is reproducible. Unit and functional testing procedures are fully automated in Rails.

When we test a Rails application, we don't view it using a traditional web browser. Instead, tests are invoked from the command line, and can be run as background processes. The testing environment provides a dedicated environment in which these processes can operate.

Production

By the time your application finally goes live, it should be well tested, so that all (or at least most) of the bugs have been eliminated. As a result, updates to the code base should be infrequent, which means that the production environments can be optimized to focus on performance. Tasks such as writing extensive logs for debugging purposes should be unnecessary at this stage. Besides, if an error does occur, you don't want to scare your visitors away with a cryptic stack trace -- that's best kept for the development environment.

As the requirements of each of the three environments are quite different, Rails stores the data for each environment in entirely separate databases. So at any given time, you might have:

  • live data with which real users are interacting in the production environment
  • a partial copy of this live data that you're using to debug an error or develop new features in the development environment
  • a set of testing data that's constantly being reloaded into the testing environment

Let's look at how we can configure our database for each of these environments.

Database Configuration

Configuring the database for a Rails application is frighteningly easy -- all of the critical information is contained in just one file. We'll take a look at it now, then create some databases for our application to use.

The Database Configuration File

The separation of environments is reflected in the Rails database configuration file database.yml. We saw a sample of this file back in Chapter 1, Introducing Ruby on Rails, and in fact we created our very own configuration file in Chapter 2, Getting Started, when we used the rails command. Go take a look! It lives in the config subdirectory of our Shovell application.

With the comments removed, the file should look like this (Depending on your MySQL configuration, you may need to use 127.0.0.1 as your host value, instead oflocalhost.):

Example 4.1. 01-database.yml

development:
adapter: mysql
database: shovell_development
username: root
password:
host: localhost
test:
adapter: mysql
database: shovell_test
username: root
password:
host: localhost
production:
adapter: mysql
database: shovell_production
username: root
password:
host: localhost

This file lists the minimum amount of information we need in order to connect to the database server for each of our environments (development, test, and production). With the default setup of MySQL that we installed in Chapter 2, Getting Started, we can be confident to proceed with our development using the root user and an empty password for the time being -- all of our development should take place on a local machine, so we needn't be concerned about someone accessing our super-secret Shovell application.

The parameter database sets the name of the database that's to be used in each environment. As the configuration file suggests, Rails is able to support multiple databases in parallel. Note that we're actually talking about different databases here, not just different tables -- each database can host an arbitrary number of different tables in parallel. Figure 4.1 shows a graphical representation of this architecture.

1562_fig4.1
Figure 4.1. The database architecture of a Rails application

However, there's one vital aspect missing from our current configuration: the databases referenced in our configuration file don't exist yet! Let's create them now.

We can create these databases using one of the many graphical front ends that are available for MySQL, or we can just jump into the command line. Because the commands are fairly simple, let's create the databases from the command line for now; we'll look at graphical database clients later in this chapter.

Creating the Databases

To launch the MySQL command line interface, type mysql -u root at the command prompt. (On a Mac, the command is called mysql5 instead of mysql -- Mac users like to be different.)

$ mysql -u root
mysql>

The command to create a new database is simple enough: create database newdatabasename.

We'll use it to create three databases -- one for each of our environments -- as shown in Figure 4.2.

Example 4.2. 02-create-databases.sql

CREATE DATABASE shovell_development;
CREATE DATABASE shovell_test;
CREATE DATABASE shovell_production;

Database Security and the root User
If you have any experience with databases, you might be feeling a little uncomfortable that we're developing our application using the root user, without even setting a password. The reasoning behind this advice is as follows:

1. The default configuration of MySQL is such that connections to the database server can only be made from the same machine. This means that nobody -- whether they're sitting next to you, or working from the other side of the world -- will be able to wreak havoc in your Rails development environment.
2. The MySQL command line and permissions system are complex and powerful tools, and database security is a topic that's definitely beyond the scope of this book.

Of course, this is not a configuration that I would recommend for your production environment, but we'll get into that in Chapter 12, Deployment and Production Use. If you're interested in securing the database in your development environment, the MySQL manual contains some post-installation instructions [6] that should serve you well.

1562_fig4.2
Figure 4.2. Creating a database for each environment

Now that our databases exist, we can use them to store data for our application!

development is the Default Database
By default, all Rails applications use the development environment unless specified otherwise. So any Rails commands that you execute from the command line will, for the time being, only affect the data in the development database. In Chapter 12, Deployment and Production Use, we'll learn how to switch to the production environment.

The Model-view-controller Architecture

The model-view-controller (MVC) architecture that we first encountered in Chapter 1, Introducing Ruby on Rails is not unique to Rails. In fact, it pre-dates both Rails and the Ruby language by many years. However, Rails really takes the idea of separating an application's data, user interface, and control logic to a whole new level.

Let's take a look at the concepts behind building an application using the MVC architecture. Once we have the theory in place, we'll see how it translates to our Rails code.

MVC in Theory

MVC is a pattern for the architecture of a software application. It separates an application into the following three components:

  • models, for handling data and business logic
  • controllers, for handling the user interface and application logic
  • views, for handling graphical user interface objects and presentation logic

This separation results in user requests being processed as follows:

  1. The browser, on the client, sends a request for a page to the controller on the server.

  2. The controller retrieves the data it needs from the model in order to respond to the request.

  3. The controller renders the page and sends it to the view.

  4. The view sends the page back to the client for the browser to display.

This process is illustrated in Figure 4.3.

1562_fig4.3
Figure 4.3. Processing a page request in an MVC architecture

Separating a software application into these three distinct components is a good idea for a number of reasons, including the following:

  • It improves scalability (the ability for an application to grow): if your application begins experiencing performance issues because database access is slow, for example, you can upgrade the hardware running the database without other components being affected.
  • It makes maintenance easier: because the components have a low dependency on each other, making changes to one (to fix bugs or change functionality) does not affect another.
  • It promotes reuse: a model may be reused by multiple views, and vice versa.
  • It makes the application distributable: a distinct separation of code between components means that each of them could potentially reside on a separate machine, if necessary.

If you haven't quite got your head around the concept of MVC yet, don't worry. For now, the important thing is to remember that your Rails application is separated into three distinct components. Jump back to Figure 4.3 if you need to refer to it later on.

MVC the Rails Way

Rails implements the concept that models, views, and controllers should be kept quite separate by storing the code for each of these elements as separate files, in separate directories.

1562_fig4.4
Figure 4.4. The app subdirectory

This is where the Rails directory structure that we created back in Chapter 2, Getting Started comes into play. The time has come for us to poke around a bit within that structure. If you take a look inside the app directory, which is depicted in Figure 4.4, you'll see some folders whose names might be starting to sound familiar.

As you can see, each component of the model-view-controller architecture has its place within the app subdirectory -- the models, views, and controllerssubdirectories, respectively. (We'll talk about that helpers directory in Chapter 6, Helpers, Forms, and Layouts.)

This separation continues within the code that comprises the framework itself. The classes that form the core functionality of Rails reside within the following modules:

  • ActiveRecord - ActiveRecord is the module for handling business logic and database communication. It plays the role of model in our MVC architecture. While it might seem odd that ActiveRecord doesn't have the word "model" in its name, there is a reason for this: Active Record is also the name of a famous design pattern -- one that this component implements in order to perform its role in the MVC world. Besides, if it had been called ActionModel, it would have sounded more like an overpaid Hollywood star than a software component...
  • ActionController - ActionController is the component that handles browser requests and facilitates communication between the model and the view. Your controllers will inherit from this class. It forms part of the ActionPack library, a collection of Rails components that we'll explore in depth in Chapter 5, Models, Views, and Controllers.
  • ActionView - ActionView is the component that handles the presentation of pages returned to the client. Views inherit from this class, which is also part of theActionPack library.

Let's take a closer look at each of these components in turn.

ActiveRecord (the Model)

ActiveRecord is designed to handle all of an application's tasks that relate to the database, including:

  • establishing a connection to the database server
  • retrieving data from a table
  • storing new data in the database

It also has a few other neat tricks up its sleeve. Let's look at some of them now.

Database Abstraction

ActiveRecord ships with a large number of database adapters to connect to a variety of popular database server packages, such as MySQL, PostgreSQL, Oracle, and Microsoft SQL Server.

The ActiveRecord module is based on the concept of database abstraction. As we mentioned in Chapter 1, Introducing Ruby on Rails, database abstraction is a way of coding an application so that it isn't dependent upon any one database. Code that's specific to a particular database server is hidden safely in ActiveRecord, and invoked as needed. The result is that a Rails application is not bound to any specific database server software. Should you need to change the underlying database server at a later time, no changes to your application code should be required.

Examples of code that differs greatly between vendors, and which ActiveRecord abstracts, include:

  • the process of logging into the database server
  • date calculations
  • handling of boolean (true/false) data

Before I can show you the magic of ActiveRecord in action, though, we need to do a little housekeeping.

Database Tables

We've already created a database for each of our environments (development, testing, production), but there aren't any tables in those databases yet. Tables are the containers within a database that store our data in a structured manner, and they're made up of rows and columns. The rows map to individual objects, and the columns map to the attributes of those objects. The collection of all the tables in a database, and the relationships between those tables, is called the database schema. An example of a table is shown in Figure 4.5.

1562_table
Figure 4.5. The structure of a typical database table, including rows and columns

In Rails, the naming of Ruby classes and database tables follows an intuitive pattern: if we have a table called stories that consists of five rows, then that table will store the data for five Story objects. The nice thing about the mapping between classes and tables is that it's not something that you need to write code to achieve -- it just happens, because ActiveRecord infers the name of the table from the name of the class. Note that the name of our class in Ruby is a singular noun (Story), but the name of the table is plural (stories).

This relationship makes sense if you think about it: when we refer to a Story object in Ruby, we're dealing with a single story. But the MySQL table holds a multitude of stories, so its name should be plural. While it's possible to override these conventions (as is sometimes necessary when dealing with legacy databases), it's much easier to adhere to them.

The close relationship between tables and objects extends even further: if our stories table were to have a link column, as our example in Figure 4.5 does, then the data in this column would automatically be mapped to the link attribute in a Story object. And adding a new column to a table would cause an attribute of the same name to become available in all of that table's corresponding objects.

So, let's create some tables to hold the stories we create.

For the time being, we'll create a table using the old-fashioned approach of entering SQL into the MySQL command line. You could type out the following SQL commands, although I acknowledge that typing out SQL isn't much fun. Instead, I'd encourage you to download the following script from the code archive, and copy and paste it straight into your MySQL console.

Example 4.3. 03-create-stories-table.sql

USE shovell_development;
CREATE TABLE `stories` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) default NULL,
`link` varchar(255) default NULL,
PRIMARY KEY (`id`)
);

You needn't worry about remembering these SQL commands to use in your own projects; instead, take heart in knowing that in Chapter 5, Models, Views, and Controllers, we'll look at something called migrations, which are special Ruby classes that we can write to create database tables for our application without using any SQL at all.

Using the Rails Console

Now that we have our stories table in place, let's exit the MySQL console and open up a Rails console. A Rails console is just like the interactive Ruby console (irb) that we used in Chapter 3, Introducing Ruby, but with one key difference: in a Rails console, you have access to all of the environment variables and classes that are available to your application while it is running. These are not available from within a standard irb console.

To enter a Rails console, change to your shovell folder, and enter the command ruby script/console, as shown below. The >> prompt is ready to accept your commands:

$ cd shovell
$ ruby script/console
Loading development environment.
>>

Saving an Object

To start using ActiveRecord, simply define a class that inherits from the ActiveRecord::Base class. (We touched on the :: operator very briefly in Chapter 3, Introducing Ruby, where we used it to refer to constants. It can also be used to refer to classes that exist within a module, which is what we're doing here.) Flip back to the section on object oriented programming (OOP) in Chapter 3, Introducing Ruby if you need a refresher on inheritance.

Consider the following code snippet:

class Story < class="Apple-converted-space">
end

These two lines of code define a seemingly empty class called Story. However, this class is far from empty, as we'll soon see.

From the Rails console, let's create this Story class, and an instance of the class called story, by entering these commands:

>> class Story < class="Apple-converted-space">
=> nil
>> story = Story.new
=> #nil, "name"=>nil},
@new_record=true>
>> story.class
=> Story

As you can see, the syntax for creating a new ActiveRecord object is identical to the syntax we used to create other Ruby objects in Chapter 3, Introducing Ruby. At this point, we've created a new Story object. However, this object exists in memory only -- we haven't stored it in our database yet.

We can confirm the fact that it hasn't been saved yet by checking the value of the new_record attribute, using the object's accessor method:

>> story.new_record?
=> true

Because the object has not been saved yet, it will be lost when we exit the Rails console. To save it to the database, we need to invoke the object's save method:

>> story.save
=> true

Now that we've saved our object (a return value of true indicates that the save method was successful) our story is no longer a new record. It's even been assigned a unique ID, as shown below:

>> story.new_record?
=> false
>> story.id
=> 1

Defining Relationships Between Objects

As well as the basic functionality that we've just seen, ActiveRecord makes the process of defining relationships (or associations) between objects as easy as possible. Of course, it's possible with some database servers to define such relationships entirely within the database schema. However, in order to put ActiveRecord through its paces, let's look at the way it defines these relationships within Rails.

Object relationships can be defined in a variety of ways; the main difference between these relationships is the number of records that are specified in the relationship. The primary types of database associations are:

  • one-to-one associations
  • one-to-many associations
  • many-to-many associations

Let's look at some examples of each of these associations. Feel free to type them into the Rails console if you like, for practice. Remember that your class definitions won't be saved, though -- I'll show you how to define associations in a file later.

Suppose our application has the following associations:

An Author can have one Weblog:

class Author < class="Apple-converted-space">
has_one :weblog
end

An Author can submit many Stories:

class Author < class="Apple-converted-space">
has_many :stories
end

A Story belongs to an Author:

class Story < class="Apple-converted-space">
belongs_to :author
end

A Story has, and belongs to, many different Topics:

class Story < class="Apple-converted-space">
has_and_belongs_to_many :topics
end
class Topic < class="Apple-converted-space">
has_and_belongs_to_many :stories
end

You're no doubt growing tired of typing class definitions into a console, only to have them disappear the moment you exit the console. For this reason, we won't go any further with the associations between our objects -- we'll delve into the ActiveRecord module in more detail in Chapter 5, Models, Views, and Controllers.

The ActionPack Module

ActionPack is the name of the library that contains the view and controller parts of the MVC architecture. Unlike the ActiveRecord module, these modules are a little more intuitively named: ActionController and ActionView.

Exploring application logic and presentation logic on the command line doesn't make a whole lot of sense (views and controllers are designed to interact with a web browser, after all!). Instead, I'll just give you a brief overview of the ActionPack components, and we'll cover the hands-on stuff in Chapter 5, Models, Views, and Controllers.

ActionController (the Controller)

The controller handles the application logic of your program, acting as a glue between the application's data, the presentation layer, and the web browser. In this role, a controller performs a number of tasks, including:

  • deciding how to handle a particular request (for example, whether to render a full page or just one part of it)
  • retrieving data from the model to be passed to the view
  • gathering information from a browser request, and using it to create or update data in the model

When we introduced the MVC diagram in Figure 4.3 earlier in this chapter, it might not have occurred to you that a Rails application can consist of a number of different controllers. Well, it can! Each controller is responsible for a specific part of the application.

For our Shovell application, we'll create:

  • one controller for displaying story links, which we'll name StoryController
  • another controller for handling user authentication, called AccountController

Both controllers will inherit from the ActionController::Base class, but they'll have different functionality, implemented as instance methods. (There will actually be an intermediate class between this class and the ActionController::Base class; we'll cover the creation of the StoryController class in more detail in Chapter 5, Models, Views, and Controllers. However, this doesn't change the fact that ActionController::Base is the base class from which every controller inherits. Here's a sample class definition for the StoryController class:

class StoryController < class="Apple-converted-space">
def index
end
def show
end
end

This simple class definition sets up our StoryController with two empty methods -- the index method, and the show method -- both of which we'll expand upon in later chapters.

Naming Classes and Files
You'll have noticed by now that the names of classes and files follow different conventions:

  • Class names are written in CamelCase (each word beginning with a capital letter, with no spaces between words).
  • Filenames are written in lowercase, with underscores separating each word.

This is important! If this convention is not followed, Rails will have a hard time locating your files. Luckily, you won't need to name your files manually very often, if ever, as you'll see when we look at generated code in Chapter 5, Models, Views, and Controllers.

Each controller resides in its own Ruby file (with a .rb extension), which lives within the app/controllers directory. The StoryController class that we just defined, for example, would live in the file app/controllers/story_controller.rb.

ActionView (the View)

As we discussed earlier, one of the principles of MVC is that a view should contain presentation logic only. This means that the code in a view should only perform actions that relate to displaying pages in the application -- none of the code in a view should perform any complicated application logic, nor should it store or retrieve any data from the database. In Rails, everything that is sent to the web browser is handled by a view.

Predictably, views are stored in the app/views folder of our application.

A view need not actually contain any Ruby code at all -- it may be that one of your views is a simple HTML file. However, it's more likely that your views will contain a combination of HTML and Ruby code, making the page more dynamic. The Ruby code is embedded in HTML using embedded Ruby (ERb) syntax.

ERb is similar to PHP or JSP, in that it allows server-side code to be scattered throughout an HTML file by wrapping that code in special tags. For example, in PHP you might do something like this:

The equivalent in ERb would be the following:

<%= 'Hello World from Ruby!' %>

There are two forms of the ERb tag pair: one that includes the equal sign, and one that does not:

<%= ... %>

This tag pair is for regular output. The output of a Ruby expression between these tags will be displayed in the browser.

<% ... %>

This tag pair is for code that is not intended to be displayed, such as calculations, loops, or variable assignments.

An example of each is shown below:

<%= 'This line is displayed in the browser' %>
<% 'This line executes silently, without displaying any output' %>

You can place any Ruby code -- be it simple or complex -- between these tags.

Creating an instance of a view is a little different to that of a model or a controller. While ActionView::Base (the parent class for all views) is one of the base classes for views in Rails, the instantiation of a view is handled completely by the ActionView module. The only thing a Rails developer needs to modify is the template, which is the file that contains the presentation code for the view. As you might have guessed, these templates are stored in the app/views folder.

As with most things in Rails, a strict convention applies to the naming and storage of template files:

  • A template has a one-to-one mapping to the action (method) of a controller. The name of the template file matches the name of the action to which it maps.
  • The folder that stores the template is named after the controller.
  • The extension of the template file varies on the basis of the template's type. By default there are three types of template in Rails:
    • rhtml - This is the extension for standard HTML templates that are sprinkled with ERb tags.
    • rxml - This extension is used for templates that output XML (for example, to generate RSS feeds for your application).
    • rjs - This extension is used for templates that return JavaScript instructions. This type of template might be used, for example, to modify an existing page (via Ajax) to update the contents of a
      tag.

This convention may sound complicated, but it's actually quite intuitive. For example, consider the StoryController class that we defined earlier. Invoking the read method for this controller would, by default, attempt to display the ActionView template that lived in the app/views/story directory. Assuming the page was a standard HTML page (containing some ERb code), the name of this template would be read.rhtml.

Rails also comes with special templates such as layouts and partials. Layouts are templates that control the global layout of an application, such as structures that remain unchanged between pages (the primary navigation menu, for instance). Partials are special subtemplates (the result of a template being split into separate files, such as a secondary navigation menu or a form) that can be used multiple times within the application. We'll cover both layouts and partials in Chapter 7, Ajax and Web 2.0.

Communication between controllers and views occurs via instance variables that are populated from within the controller's action. Let's expand upon our sampleStoryController class to illustrate this point (there's no need to type any of this out just yet):

class StoryController < class="Apple-converted-space">
def index
@variable = 'Value being passed to a view'
end
end

As you can see, the instance variable @variable is being assigned a string value within the controller's action. Through the magic of ActionView, this variable can now be referenced directly from the corresponding view, as shown in the code below:

The instance variable @variable contains: <%= @variable %>

This approach allows more complex computations to be performed outside the view (remember, it should only contain presentational logic), leaving the view to display just the end result of the computation.

Rails also provides access to special containers, such as the params and session hashes. These contain information including the current page request and the user's session. We'll make use of these hashes in the chapters that follow.

Code Generation

Rather than having us create all of our application code from scratch, Rails gives us the facility to generate an application's basic structure with considerable ease. In the same way that we created our application's entire directory structure, we can create new models, controllers, and views using a single command.

To generate code in Rails, we use the generate script, which lives in the script folder. Give it a try now: type ruby generate without any command line parameters. Rails displays an overview of the available parameters for the command, and lists the generators from which we can choose, as Figure 4.6 illustrates.

1562_fig4.6
Figure 4.6. Sample output from script/generate

Rails can generate code of varying complexity. At its simplest, creating a new controller causes a template file to be placed in the appropriate subdirectory of your application. The template itself consists of a mainly empty class definition, similar to the Story and Author classes that we looked at earlier in this chapter.

However, code generation can also be a very powerful tool for automating complex, repetitive tasks; for instance, you might generate a foundation for handling user authentication. We'll launch straight into generating code in Chapter 5, Models, Views, and Controllers, when we begin generating our models and controllers.

Another example is the generation of a basic web-based interface to a model, referred to as scaffolding. We'll also look at scaffolding in Chapter 5, Models, Views, and Controllers, as we make a start on building our views.

ActionMailer

While not strictly part of the Web, email is a big part of our online experience, and Rails's integrated support for email is worth a mention. Web applications frequently make use of email for tasks like sending sign-up confirmations to new users and resetting a user's password.

ActionMailer is the Rails component that makes it easy to incorporate the sending and receiving of email into your application. ActionMailer is structured in a similar way to ActionPack in that it consists of controllers and actions with templates.

While the creation of emails, and the processing of incoming email, are complex tasks, ActionMailer hides these complexities and handles the tasks for you. This means that creating an outgoing email is simply a matter of supplying the subject, body, and recipients of the email using templates and a little Ruby code. Likewise,ActionMailer processes incoming email for you, providing you with a Ruby object that encapsulates the entire message in a way that's easy to access.

Adding email functionality to a web application is beyond the scope of this book, but you can read more about ActionMailer on the Ruby on Rails wiki.

Testing and Debugging

Testing

A number of different types of testing are supported by Rails, including automated and integration testing.

Automated Testing

The concept of automated testing isn't new to the world traditional software development, but it's fairly uncommon in web application development. While most Java-based web applications make use of comprehensive testing facilities, a large number of PHP and Perl web applications go live after only some manual tests have been performed (and sometimes without any testing at all!). Although performing automated tests may be an option, developers may decide not to use them for reasons ranging from the complexity of the task to time constraints.

We touched on this briefly in Chapter 1, Introducing Ruby on Rails, but it's worth stressing again: the fact that comprehensive automated testing is built into Rails, and is dead easy to implement, means there's no longer a question about whether or not you should test your apps: just do it!

The generate command that we introduced a moment ago can automatically create testing templates that you can use with your controllers, views, and models. (Note that Rails just assists you in doing your job, it's not replacing you -- yet!)

The extent to which you want to implement automated testing is up to you. It may suit your needs to wait until something breaks, then write a test that proves the problem exists. Once you've fixed the problem so that the test no longer fails, you'll never get a bug report for that particular problem again.

If, on the other hand, you'd like to embrace automated testing completely, you can write tests to ensure that a specific HTML tag exists at a precise position within a page's hierarchy. (The hierarchy referred to here is the Document Object Model (DOM), a W3C standard for describing the hierarchy of an (X)HTML page.) Yes, automated tests can be that precise.

Integration Testing

Rails's testing capabilities also include integration testing.

Integration testing refers to the testing of several web site components in succession -- typically, the order of the components resembles the path that a user would follow when using the application. You could, for example, construct an integration test that reconstructs the actions of a user clicking on a link, registering for a user account, confirming the registration email you send, and visiting a page that's restricted to registered users.

We'll look at both automated testing and integration testing in more detail in later chapters.

Debugging

When you're fixing problems, the first step is to identify the source of the problem. Like many languages, Rails assists this process by providing the developer (that's you!) with a full stack trace of the code. As we saw earlier, a stack trace is a list of all of the methods that were called up to the point at which an exception was raised. The list includes not only the name of each method, but also the classes to which those methods belong, and the names of the files in which they reside.

Using the information contained in the stack trace, you can go back to your code to determine the problem. There are a few different ways to approach this, depending on the nature of the problem itself:

  • If you have a rough idea of what the problem might be, and are able to isolate it to your application's model (either a particular class or aspect of your data), your best bet is to use the Rails console that we looked at earlier in this chapter. Type console from the script directory to launch the console. Once inside, you can load the particular model that you're interested in, and poke at it to reproduce and fix the problem.
  • If the problem leans more towards something related to the user's browser or session, you can add a breakpoint statement around the spot at which the problem occurs. With this in place, you can reload the browser and step through your application's code using the breakpointer command line tool to explore variable content or to execute Ruby statements manually.

We'll be covering all the gory details of debugging in Chapter 11, Debugging, Testing, and Benchmarking.

A GUI Tool for MySQL

The MySQL command line that we've been using in this chapter is one way to maintain your database structure and the data that it contains. But working in a command line client can definitely be overwhelming, complex, and tedious -- especially when you're just taking your first steps with databases and don't know your way around!

A GUI tool available for use with MySQL that's worth a mention is the MySQL Query Browser. Published by MySQL AB (the makers of MySQL), the MySQL Query Browser is a free, cross-platform tool that is currently available for Windows, Linux, and Mac OS X. The MySQL Query Browser is available for download fromhttp://dev.mysql.com/downloads/query-browser/ [7]. Unfortunately there is no binary install package for OS X 10.3 or earlier; CocoaMySQL is a good alternative.

Installing MySQL Query Browser is a straightforward process on most platforms:

  • Windows - A binary installer exists for Windows -- launch the installer and select the default options for each step in the wizard.
  • Mac OS X - A binary installer exists for the Mac as well. Mount the disk image and drag the application icon to your Applications folder.
  • Linux - A package exists for most distributions of Linux; install the application using your distribution's package manager.

1562_fig4.7
Figure 4.7. The MySQL Query Browser connection screen

The MySQL Query Browser can be used to perform queries against your database. You can also use it to alter your database structure by creating and modifying databases and tables. Figure 4.7 shows the connection screen.

The connection details to use are identical to the ones we used earlier, when we configured Rails to connect to our database in the config/database.yml file. Assuming that you haven't changed your MySQL configuration since then, enter localhost into the Hostname field and root for the Username. Now hit Connect.

Once you're connected, you should be greeted by a window similar to the one shown in Figure 4.8.

1562_fig4.8
Figure 4.8. MySQL Query Browser's Query window

At the top of the main window is a text field in which you can type database queries. The pull-out tab on the right-hand side lists the databases to which you can connect. There's even a function and syntax reference.

The MySQL Query Browser displays the table schema of the stories table exactly as we've created it, with the added benefit that we can alter it with just a mouse click. By clicking the + button at the bottom of the column list, you can add a column; clicking the - button removes the currently selected column. Pretty simple, isn't it?

Exploring every feature of the query browser is definitely beyond the scope of this book, but there is one more thing I'd like to show you: the Table Editor, which is shown in Figure 4.9.

To launch the Table Editor, first expand the shovell_development database by clicking on the triangle next to the database's name. This will list all of the tables in the database. Currently, there should only be one: the stories table that we created earlier. Now right-click (Control-click on a Mac) on the table that you want to edit, and select Edit Table from the menu that appears.

1562_fig4.9
Figure 4.9. The MySQL Table Editor

The Table Editor allows you to edit existing tables and add new tables, all using a nice GUI interface. I'm sure you'll agree this is a much friendlier experience than having to battle with the cryptic command line tool.

That's it for the MySQL Query Browser -- we'll revisit it briefly in Chapter 5, Models, Views, and Controllers, but feel free to close the application now.

Summary

In this chapter, we peeled back some of the layers that comprise the Ruby on Rails framework. By now you should have a good understanding of which parts of Rails perform particular roles in the context of an MVC architecture. It should also be reasonably clear how a request that's made by a web browser is processed by a Rails application.

We looked at the different environments that Rails provides to address the different stages in the lifecycle of an application, and we created databases to support these environments. We also provided Rails with the necessary details to connect to our database.

We also had our first contact with real code, as we looked at the ActiveRecord models, ActionController controllers, and ActionView templates for our clone of digg.com[8], Shovell. We explored the topics of code generation, testing, and debugging, and we took a brief look at a GUI client that makes interacting with our MySQL database more convenient.

In the next chapter, we'll build on all of this knowledge as we use the code generation tools to create actual models, controllers, and views for our Shovell application. It's going to be a big one!

That's it for this excerpt of Build Your Own Ruby On Rails Web Applications [9] -- but don't forget that the downloadable PDF contains three more chapters [10] than are included here. See the complete Table of Contents [11] for the full details of what's covered in this book.

[1] http://www.ruby-doc.org/stdlib/
[2] http://www.sitepoint.com/books/rails1/
[3] http://www.sitepoint.com/popup/popup.php?zone=2&popupid=92
[4] http://en.wikipedia.org/wiki/Knight_rider/
[5] http://www.sitepoint.com/article/javascript-library/
[6] http://dev.mysql.com/doc/refman/5.0/en/post-installation.html
[7] http://dev.mysql.com/downloads/query-browser/
[8] http://digg.com/
[9] http://www.sitepoint.com/books/rails1/
[10] http://www.sitepoint.com/popup/popup.php?zone=2&popupid=92
[11] http://www.sitepoint.com/books/rails1/toc.php