Fortunately, you don’t need to know a whole lot of Ruby to get real work done with Rails. The creators of Rails have used many of Ruby’s most advanced features to make Rails easy to work with, but fortunately you can enjoy the benefits without having to know the details. This Appendix explains the basics you’ll need to perform typical tasks in Rails and should help you get started. For a lot more detail on Ruby, try Learning Ruby (O’Reilly, 2007), The Ruby Programming Language (O’Reilly, 2008), the Ruby Pocket Reference (O’Reilly, 2007), or Programming Ruby (Pragmatic Programmers, 2004).
This excerpt is from Learning Rails . Most Rails books are written for programmers looking for information on data structures. Learning Rails targets web developers whose programming experience is tied directly to the Web. Rather than begin with the inner layers of a Rails web application -- the models and controllers -- this unique book approaches Rails development from the outer layer: the application interface. You can start from the foundations of web design you already know, and then move more deeply into Ruby, objects, and database structures.
If you’ve never worked with a programming language before, this Appendix may go too fast for you. It’s hard to be incredibly brief and cover the basic basics at the same time. However, if you’ve worked with JavaScript before, you should be able to get started here.
Ruby is a beautiful but sometimes mystifying language, and probably a better choice as a second language to learn rather than a first language.
Because this is a Rails book, examples will work inside of the Rails framework, in a Rails view and controller, rather than from the command line. If you haven’t touched Rails before, it makes sense to read Chapter 1, Starting Up Ruby on Railsfirst and get Rails installed, and then come back here for more instruction.
Ruby is an object-oriented language. Although it’s often compared to Perl, because Ruby code often looks like Perl, Ruby’s object-orientation goes much deeper. Practically everything in Ruby is an object.
What does that mean?
Objects are combinations of logic and data that represent a (usually mostly) coherent set of tasks and tools for getting them accomplished. Programming objects aren’t quite as concrete as objects in the real world, often created and destroyed (or at least abandoned for cleanup later) in fractions of a second. Nonetheless, in those brief moments—or in the hours, days, or years they could also exist—they provide a practical means of getting things done.
In some sense, a program is a big toolchest filled with these objects, and programming is about assembling objects to put into the chest. Ruby provides some starter objects and a means of creating new objects and, of course, ways to start these objects interacting with each other so that the program actually runs.
There are a few other important things to know about Ruby. They’re probably most important if you’re coming to Ruby from other programming languages that have different expectations, but they all affect the way you’ll write Ruby programs:
Ruby is an interpreted language, meaning that Ruby reads through the code and decides how to execute it while it’s running, rather than reading it and turning it into a highly optimized set of instructions before it actually runs. (There are a few people working on ways to create a compiled Ruby, but that’s unusual.) While that slows things down, it also adds a lot of flexibility.
Ruby also has really flexible syntax expectations. Most of the time this makes things easier—you don’t need to type parentheses around method parameters most of the time. Other times, however, you’ll find yourself facing mysterious error messages because you didn’t include parentheses and the situation is slightly ambiguous. (This book tries to warn you about these kinds of situations when they appear in Rails.)
Ruby uses dynamic typing.[2] Some languages (notably Java, C, and C++) expect that the programmer will always know, and always specify, the kind of information they expect to store in a given information container, a variable. Locking that down in advance makes it easy to do some kinds of optimization. Ruby has taken another path, leaving variables open enough to contain any kind of information and be created at any time. Again, this allows for a much more flexible approach, in which operations can change what they do based on context. Sometimes, however, it means that things can go wrong in strange and unpredictable ways if something unexpected is in a variable.
Ruby supports blocks and closures. You don’t need to know how to create methods that work with blocks or closures in order to use Rails, but you definitely do need to know how to call methods that expect a block of code as an argument. At first, your best choice for dealing with these features will be to look at sample code and use it as a foundation rather than trying to step back and figure out how this should work in the abstract.
Ruby lets advanced developers perform metaprogramming, even creating Domain Specific Languages (DSLs), which are kind of like their own miniature programming language focused on a particular task. You don’t need to know how to do metaprogramming to use Rails, but you should be aware that Rails uses these techniques. Sometimes you’ll encounter something that claims to be Ruby but seems very strange and too specialized to be part of the Ruby language. Odds are good that metaprogramming is involved. As with blocks and closures, it’s often best to start out by emulating sample code to work toward figuring it out.
Ruby is a very powerful language. It’s not hard to get started in Ruby, but you should at least be aware of these powerful techniques so you can recognize them when you encounter them. Knowing that these possibilities exist may help reduce your frustration when you encounter mysterious difficulties.
Rails is a set of Ruby objects that together make up a framework. Installing Rails is a first step toward building an application, but while it gives you many useful objects that can run happily in a web environment, there’s a lot missing, a lot you have to provide.
You can buy a beehive—a set of boxes with frames that the bees will inhabit and fill with honey. It’ll have a top, a base, an entrance, a number of useful architectural features, and a nice coat of paint. It looks like a beehive when it’s set up. Unfortunately, setting up a beehive is just the first step. To make a beehive work, you have to add bees, who will finish building their home, collect useful nectar and pollen, and make the hive interact with the world.
Rails gives you an empty beehive. You don’t add bees, exactly, but you do populate it with your own logic. That logic turns Rails from an empty container into a dynamic application, connected to the outside world and performing the tasks you define.
The rest of this Chapter will teach Ruby within the Rails framework, explaining the language in the context you’ll likely be using it.
If you haven’t installed Rails yet, take a look at Chapter 1, Starting Up Ruby on Rails. It might be easiest to use Heroku, a web-based implementation that will spare you having to really install Rails before getting started. On the other hand, if you want to stay at the command line, you can also run much of this code in irb, the Ruby command-line interface described in Chapter 11, Debugging.
Most of the Rails files you’ll work with and create define classes. (They do so even when they don’t have explicit class definitions, as Rails performs some of its magic in the background.) The clearest place to work with objects in Rails is in the controller classes. To get started, therefore, go to the command line and create a new application and a new controller:
rails testbed...cd testbed...ruby script/generate controller Testbed index
If you’re using Heroku, instead of going to the command line, log in to
Heroku and click on the Create A New Application button from the My
Apps page. You can rename it “testbed” if you want, but the
application name doesn’t matter much. What does matter is that when
the application editing screen opens, you click on the gear menu near
the bottom left, choose Generate, and enter controller Testbed index. That will set
things up for the rest of these examples.
For the rest of this appendix, there are only two files that
matter: app/views/testbed/index.html.erb and
app/controllers/testbed_controller.rb. For
right now, replace the contents of app/views/testbed/index.html.erb with:
<%= @result %>
That will make it easy to see the results of the code in the
controller, which is a clearer place to explore Ruby. (@result is a variable whose value various
examples will set.)
If you open app/controllers/testbed_controller.rb, you’ll
see the code below. It doesn’t yet do anything, except tell the
programmer what it is and what it derives from:
class TestbedController < ApplicationController def index end end
The first line, class TestbedController
< ApplicationController, tells you two important things. First, it tells you that
this file contains a class definition, for a class named TestbedController. Second, it tells you—you
can read < as “inherits from”—that
this class is descended from ApplicationController. Even though this file
is basically empty, it inherits a lot from ApplicationController. Well, actually, even
though ApplicationController is
almost as empty (see app/controllers/application.rb if you’re
curious), it inherits from ActionController::Base, a key part of the Rails framework that provides a lot of
functionality for connecting controllers with requests and data.
Fortunately, one of the benefits of Rails is that you almost never need to worry what’s actually done in the superclasses, as these ancestors are called. It’s strange to say “don’t look” in a tutorial—but you really don’t have to look, and certainly not at first.
The next two lines define an empty method, index, which the next section will improve on.
Finally, the closing end brings the
definition of the TestbedController
class to its conclusion.
So, this is a class. What’s an object?
An object is an instance of a class. This
class defines what a TestbedController looks like. When Rails gets
a request that it thinks requires a TestbedController, it reads the class
definition and creates an object that will perform as that class
specifies. If necessary, Rails will create places to store the object’s
data as well as connections to call its methods. Rails may create many
different TestbedController objects
at the same time (one per request), but all will use the same
definition. The process of creating an object from a class definition is
called instantiation.
While they don’t actually do anything in a Ruby program, comments are critical for making code readable, especially complicated code. Ruby comments start with a # character and continue to the end of that line. If a line starts with #, then the entire line is a comment. If a line starts with code and then includes a # (outside of a quoted string or regular expression), then everything to the right of the # is considered a comment and ignored. For example:
# This whole line is a commentx = 2# x is assigned the value 2, and the comment is ignored.
Comments are useful for humans, especially when you read someone else’s code or return to a project after a long while away, but Ruby will just ignore them.
TestbedController is a pretty
dull class so far. If you start Rails (with ruby script/server, the >> button in Heroku, or whatever does it
in the environment you’ve installed), and visit http://localhost:3000/testbed/, you’ll get a mostly blank
response. There’s nothing in @result,
because TestbedController’s index method doesn’t actually do
anything.
That’s easily fixed. Change the definition of index to:
def index
@result = 'hello'
endNow, when you load the page, you’ll see “hello” as the result. (This is not exciting enough to deserve a screenshot.)
@result is a variable, a container for information. Because the name
of the variable started with @, it
is an instance variable, connected to the object in such a way that other
objects can see it. That let the view retrieve it to shows its value.
The new line of code assigned (=)
an expression to the @result
variable, the string hello.
The string was surrounded with single quotes (') to
indicate that it was a string, a series of characters, rather than
another variable name or something else entirely. If you need to
include an apostrophe or single quote inside of a single-quoted
string, just put a backslash (\) in
front of the quote, as in 'Hello! Ain\'t it a
pretty day?'. This is called escaping
the quote, hiding it from normal processing.
Ruby also lets you surround strings with double quotes. Double-quoted strings offer a lot more escaping functionality, but single-quoted strings are simpler and faster to work with. If you’re used to putting double quotes around strings, that will still work, but you may want to explore the documentation to learn what you’re getting yourself into.
@result could take a variety
of different kinds of values; Ruby isn’t picky about what goes into
its variable containers. You can assign it numbers, objects, boolean
values—pretty much anything that comes to mind in Ruby work. Ruby will
do its best to figure out what to do with the values you assign to
your variables. For example, you could write:
def index one = 1 two = 2 @result = one + two end
The value of @result would be
3, what you get for evaluating the
expression one + two, which leads
to adding 1 and 2. (Note that one and two are local
variables—they don’t have an @ in front of their names, and are only
available within the index method.)
If, however, you’d written:
def index one = 'one' two = 'two' @result = one + two end
The value of @result would be
onetwo, because the plus operator (+)
combines strings sequentially (also called
concatenating them) instead of adding their
numeric values. When Ruby runs that line of code, it checks to see
what types are in the values before deciding how the operator will
behave.
Ruby isn’t as flexible as some other dynamically typed
languages. If you set one to
'one' and two to 2, you’d get the error message “can't convert Fixnum into String.” Ruby
may not keep close track of what types your variables have, but
effectively it’s your responsibility to do so.
While programmers often think of their code as determining the main flow of logic through an application, from a user’s point of view most of what’s interesting is what happens to the variables. Does data go to the right place? Is it stored properly? What are the results of calculations on that data?
Variables are the places you store that data as they follow
these paths through your applications. You can assign values to
variables and change those values. You can perform operations on those
values (like +, –, *,
/, and much, much more), and pass
variables to methods as arguments.
Sometimes a variable should hold more than just one value. It needs to contain a list, a list of lists, or even a collection where values are connected to names. Ruby supports these needs with arrays, which are simple lists, and hashes, which are collections of named data.
Arrays start out simple. While you can create arrays more
programmatically with the Array
object, it’s easiest to create an array by surrounding a
comma-separated list of values with square brackets:
myArray = [1, 2, 'tweet']
The values can be any Ruby expression. This one happens to mix
two numbers and a string. You can reference specific items by
number. For example, you might redefine the index method to look like:
def index myArray = [1, 2, 'tweet'] @result = myArray[2] end
If you’ve done a lot of programming, you might not be
surprised that the @result
variable ends up containing tweet. Why? Because Ruby counts arrays
from zero, not from one. myArray[0] is 1, myArray[1] is 2, and, of course, myArray[2] is tweet.
Sometimes you’ll want to have lists containing lists. Ruby supports this by letting you put arrays inside of arrays:
myNestedArray= [ [1, 2, 'tweet'], [3, 4, 'woof'], [5, 6, 'meow'] ]
If you wanted to reach the meow, you’d go to item 2 of the overall
array, and then item 2 of the array inside of item 2, as in:
def index
myNestedArray= [ [1, 2, 'tweet'], [3, 4, 'woof'], [5, 6, 'meow'] ]
@result = myNestedArray[2][2]
endYou can mix arrays of any size you’d like inside of another array, or even mix in ordinary values. There’s no requirement that the array structure must be consistent.
Hashes are just a little more complicated. Hashes, also called maps or associative arrays, contain keys and values. Keys are effectively names that correspond to values. Within a given hash, all of the keys have to be unique. (Values can duplicate as necessary, though.) The easiest way to create a hash is with a hash literal:
myHash={ 'one' => 1, 'two' => 2, 'three' => 'tweet' }To retrieve items from the hash, just call for them by name, as in:
def index
myHash={ 'one' => 1, 'two' => 2, 'three' => 'tweet' }
@result = myHash['two']
endIn this case, @result will
contain 2, as that corresponds to
the name two. As with arrays, you
can also create hashes through the Hash object and its methods.
Both the key and the value can have any type: you can use numbers, or strings, or, as Rails often does, especially in method calls, symbols.
Rails uses symbols—names preceded by a colon, like :courses or :students—practically everywhere. They get
used like variables, to refer to models. They get used as labels for
options in method calls. When you’re first starting out in Rails,
your best option is to study the examples and see where symbols are
used and where other kinds of variables are used. Then, just follow
the established pattern.
Why does Rails use symbols? The short answer is efficiency. Ruby handles symbols with less processing than strings. The long answer is a lot more complicated than that, involving the metaprogramming glue that holds the framework together. When you’re ready to extend the Rails framework yourself, you’ll need to learn the details. Until then, you don’t need a deep understanding.
So far, all of the action in these examples have taken place in
one method: index. You may have the
occasional controller with just one method, but most classes contain
more than one method. Methods can call each other, passing each other
data, establishing program logic through these many interconnections.
A simple demonstration in the same testbed controller can show how
this works:
class TestbedController < ApplicationController def index@result = addThem (1, 2)enddef addThem (firstNumber, secondNumber)firstNumber + secondNumberendend
When index is called, is sets
a value for @result. The expression
it uses, however, is a call to another method, addThem, which is given two arguments,
1 and 2.
The arguments are shown here in parentheses because most other languages use them, and it’s a little easier to imagine what happens. However, the parentheses are optional in Ruby and often omitted.
The addThem method specifies
that it takes two parameters, named firstNumber and secondNumber. The expression on the second
line, firstNumber + secondNumber,
will be evaluated, yielding 3. Ruby methods return the last value they
produced, so addThem will tell
index that its answer is 3.
@result will be set to 3, which
will be presented through the view.
If you prefer, you could write return
firstNumber + secondNumber, making it explicit that the
value is the return value for the method. However, you won’t see
this done frequently in other people’s Ruby code.
Because of the way Rails routing works, the addThem method is currently exposed to the
public—though there isn’t a view for it, it won’t get useful
arguments, and so on. Fortunately, Ruby offers a way to hide such
methods from public view while keeping them accessible to other
methods in the same class. Just add the keyword private before addThem is defined:
class TestbedController < ApplicationController
def index
@result = addThem (1, 2)
end
private
def addThem (firstNumber, secondNumber)
return firstNumber + secondNumber
end
endMethods that follow the private are still available to the other
methods in the class, but can no longer be called from outside of
it.
The methods explicitly listed in the TestbedController class are only a subset
of the methods the class actually contains, because of the opening
declaration:
class TestbedController < ApplicationController
All of the methods that are defined in ApplicationController will also be
available in TestbedController. If you want some
different behavior in TestbedController, you can
override methods—defining new methods with the same name and
arguments.
Chapter 8, Improving Formsshows how overriding
methods can work, but there’s frequently one small problem. As often
as not, the new method wants to do what the old method did, plus
something additional. For example, this was a method overriding the
text_field method from ActionView::Helpers::FormBuilder:
class TidyFormBuilder < ActionView::Helpers::FormBuilder
....
def text_field(method, options={})
label_for(method, options) + super(method, options)
endThe text_field method here wants to create a label, and then call the
original method that it was overriding. The call to super isn’t to a method called super—it’s to the text_field method specified in the
ActionView::Helpers::FormBuilder
class. This is a common technique when you need to tweak the
functionality the framework provides.
While you probably won’t be writing methods as sophisticated as the ones in the Rails framework itself for a little while, there are a few techniques you should understand for calling those methods.
The first, simpler one, is Rails’ frequent use of methods that take an options hash as an argument. While reading the Rails API documentation, you might encounter something like:
text_field_tag(name, value = nil, options = {})The method name is text_field_tag, and it takes a name argument and a value argument which has a default value
of nil. But what is options = {}, especially since most calls
to text_field_tag don’t even use
{ and }?
options = {} provides a way for methods to accept named parameters,
taking hash with named values specified elsewhere in the
documentation. In a more formal world, the named parameters would
form a hash literal inside of {
and }, but Ruby doesn’t require
that level of formality. You could write:
text_field_tag 'Name', 'Jim', {:maxlength => 15, :disabled => true}But more typically you’ll see:
text_field_tag 'Name', 'Jim', :maxlength => 15, :disabled => true
In general, named parameters go at the end of the method call, and the curly braces are optional. There are times, however, when the braces are necessary, as noted in the section called “Creating Checkboxes” ” section in Chapter 6, Presenting Models with Forms.
The second, harder one, is Rails’ use of methods that take an
unnamed block of code as an argument. This happens frequently
with the helper methods listed in Appendix D, A Catalog of Helper Methods, as well as in the
migration code explored in Chapter 10, Managing Databases with Migrations, but it’s a pattern
that can appear anywhere. Sometimes, as in the layout issues
discussed in Chapter 2, Rails on the Web, the block-passing
is just a quiet part of the framework, and you only notice it
because of a yield call.
The key to recognizing a method that takes a block as an
argument is the &proc or pair
of curly braces at the end of the list of arguments, and examples
that show the method wrapping around other code, usually with
do. The typical form looks pretty
similar, whether in straight Ruby code or in ERb view markup. For
example, create_table in a
migration looks like:
create_table :awards do |t|t.string :namet.integer :yeart.integer :student_id end
A form_for call, meanwhile,
looks like:
<% form_for([@student, @award]) do |f| %><%=f.error_messages %> <p> <%=f.label :name %><br /> <%=f.text_field :name %> </p> <p> <%=f.label :year %><br /> <%=f.text_field :year %> </p> <p><%=f.submit "Create" %></p> <% end %>
Each of these calls does something when it is first called.
create_table orders the creation
of a database table, while form_for creates an HTML form element.
They don’t just complete and disappear, however—they create a
context, using do, that applies
until the end statement. The
t variable and the f variable provide information that makes
it possible for the calls inside of the do to be much shorter (and much less
repetitive) than would otherwise be necessary.
When you’re working in Ruby code you’ll often use { and } in place of do and end. It’s easier to read do and end amidst the < and > of the HTML markup, though.
Rails uses blocks for other purposes as well. Chapter 2, Rails on the Web explains how the yield statement lets a method execute code
passed to it as a block when it seems convenient, and Appendix D, A Catalog of Helper Methods lists some helper methods
(notably benchmark and cache) that use blocks for their own
purposes.
Ruby attributes lie somewhere between methods and variables.
Well, actually, attributes are methods, but when used, they feel like
variables. Attributes are methods that end in =, and they get called whenever you assign a
value to the property with that name. Chapter 8, Improving Forms used a photo= method to capture incoming data when
the photo field arrived from a
form. You may find use for them eventually in your Rails development,
but at the beginning, it’s mostly useful to know the technique
exists.
Classes, variables, and simple methods may carry some basic applications a surprisingly long way, but most applications need more logic. This quick tour through Ruby’s control structures will give you more tools for building your applications.
Your program logic will depend on combining variables with operators into expressions. Those expressions then get resolved into results, which may be used to assign values to variables, or to give an answer about whether a test passed or failed. Most Ruby operators should look familiar if you’ve ever used a programming language before. The following table shows an abbreviated list of operators you’re likely to encounter in your first forays into Rails.
Operator | Use(s) |
|---|---|
| Addition, concatenation, making numbers positive |
| Subtraction, removing from collections, making numbers negative |
| Multiplication |
| Division |
| Modulo (remainder from integer division) |
| Not |
| Exponentiation (2**3 is 8, 10**4 is 1000) |
| Shift bits left, or add to a collection |
| Less than |
| Less than or equal to |
| Greater than or equal to |
| Greater than |
| General comparison—less then yields –1, equal
returns 0, greater than 1, and not comparable |
| Equal to (note that a single |
| Tests to see whether objects are of same class |
| Not equal to |
| Tests a regular expression pattern for a match (see Appendix C, An Incredibly Brief Guide to Regular Expressions) |
| Tests a regular expression pattern for no match |
| Boolean AND (use to combine test expressions) |
| Boolean OR |
| Boolean AND (lower precedence) |
| Boolean OR (lower precedence) |
| Not (lower precedence) |
| Range creator, including end value |
| Range creator, excluding end value |
defined? | Tests variable definition, returns details |
Nearly all of these can take on other meanings, as Ruby lets developers redefine them. Usually they’ll behave as you expect, but if they don’t, you may need to examine the context you’re programming in.
The if statement is
pretty much at the heart of all computer programming. Though it might
be very painful, nearly all code could be rewritten as if statements. The basic approach looks
like:
ifexpressionthingsToDoend
To create a simple example again, return to the TestbedController:
class TestbedController < ApplicationController
def index
@result = 'First is greater than or equal to last.'
first=20
last=25
if first < last
@result = 'First is smaller than last.'
end
end
endBecause the value of first is
less than the value of last, the
first < last expression will
evaluate to true, and @result will be set to First is smaller than last. For evaluation
purposes, anything except for false
or 0 or nil will evaluate to true. Definitely try changing the values of
first and last and reloading.
The if statement has a simple
opposite: unless. It performs its tasks if the expression returns
false. While you don’t really need
it, it can make some code more readable:
def index @result = 'First is smaller than last.' first=20 last=25unless first < last@result = 'First is greater than or equal to last.'endend
The unless first < last
statement means exactly the same as if
!(first < last).
Sometimes you want to do something more when your first test
fails. This calls for the else statement, which
lets you do things instead of what you had planned if your if or unless succeeded. You could rewrite these
two little methods as:
def index first=20 last=25if first < last@result = 'First is smaller than last.'else@result = 'First is greater than or equal to last.'endend
and:
def index first=20 last=25unless first < last@result = 'First is greater than or equal to last.'else@result = 'First is smaller than last.'endend
Using an else can both make
your code’s results more explicit for later developers who have to
maintain it, and support your efforts to do different things based on
a single test.
There’s one last option in regular if statements: elsif, which combines
an else and an if. You can only use it with if, not with unless, but you can have as many elsifs as you want. A simple example that
extends the logic of the previous code is:
def index
first=20
last=25
if first < last
@result = 'First is smaller than last.'
elsif first == last
@result = 'First is equal to last.'
else
@result = 'First is greater than last.'
end
endNote that it’s elsif, not
elseif, and that the double equals sign (==) tests for equality rather than assigning
a value. Using a single equals sign in a comparison is a common
mistake for new arrivals from other languages. Not only does it assign
the value, it always returns true,
satisfying the conditional test.
There is still one other variation on if that you might encounter. Instead
of:
ifexpressionthingsToDoend
it looks like:
somethingToDoifexpression
It’s more concise and sometimes more readable, but it can certainly confuse you if you’re looking for neatly indented logical statements. If you want, though, you can write:
@result = 'First is greater then last' if first > last
The ?: operator isn’t
precisely a statement, but it works like an abbreviated if/else statement. It’s mostly used in cases
where you need to return a slightly different result for one of two
cases. It starts with a test expression, then has a question mark
(?), then the value returned if the
test expression is true, then a
colon (:), and then the value
returned if the test expression is false. You could rewrite the earlier
if/else example as:
def index first=20 last=25@result = (first < last ? 'First is smaller than last.' : 'First is greater thanor equal to last.')end
Again, the message reported would be that First is smaller than last., but you can try
changing the values to see what happens.
If your if statements start
sprouting elsifs everywhere, it may
be time to switch to case and
when statements. These let you
specify an expression in the case, and then test it against various
conditions. You could rewrite the earlier test as:
def index
first=20
last=25
case
when first < last
@result ='First is smaller than last.'
when first == last
@result ='First is equal to last.'
when first > last
@result ='First is greater than last.'
end
endThere are actually many ways to write case statements. If you want to reduce
repetition, you might try:
def index
first=20
last=25
@result =case
when first < last
'First is smaller than last.'
when first == last
'First is equal to last.'
when first > last
'First is greater than last.'
end
endThis works because case
returns a value, and the when
clauses just set that value. You can also add an else clause to the end of your case statement, to catch the situation where
none of your when clauses
matched.
Evaluations are useful, but sometimes you want to just go around and around until you’ve tested something a set number of times, a particular condition is met, or you just plain run out of additional data to process. Ruby offers all kinds of ways to go around and around.
The while and until methods let
you create loops that run until the specified condition is true (while) or false (until). Both of these take a
do...end block that will be run
until the loop decides to stop. A simple example that demonstrates
this is counting. With while,
counting from 1 to 10 might look like:
def index count=1 @result =' 'while count <= 10 do@result = @result + count.to_s + " " count= count + 1endend
The first time through the loop, count starts out with a value of one, and
the condition count <= 10
evaluates to true, so Ruby
proceeds into the loop. The string value of count gets tacked onto the end of @result, with a space for clarity, and
then the value of count is
increased by one. When the end
corresponding to the do is
reached, the loop goes back to its start at while and evaluates the condition. If the
condition is still true, it goes
through the loop again; if not, it ends the loop and goes forward.
In this case it hits the end at the end of the index method, and we’re done. The view
reports @result, which is
“1 2 3 4 5 6 7 8 9 10.”
The to_s method on count converts its numeric value to a
string. The to_s method is a
general facility for turning Ruby objects into strings. You may
want to support this in your own programming, as it is often
easier to see the state of something when it can be expressed as a
string.
You could write the same thing with until, except that the condition would be
reversed:
def index count=1 @result =' 'until count > 10 do@result = @result + count.to_s + " " count= count + 1endend
You will doubtless have more exciting conditions than
incrementing variables, but remember: Rails can do many things for
you, but it won’t protect you from an infinite loop. If your
conditions aren’t met (or refused for until), your code will go on and on until
you halt it or it runs out of resources. Always make sure that the
loop will come to a halt by itself, no matter what you feed
it.
If you know how many times you want something to go around in
a loop, you can use the times
method on any numeric variable. times takes a block, marked with {}, which it will run that many times. For
example:
def index
count=3
@result =''
count.times {
@result = @result + "count "
}
endwill produce "count count
count" as the loop goes around three times.
A for loop takes a variable and a collection. In its
simplest counting approach, the collection is a range, specified
with a starting value, then two periods (..), and then an end value. The variable
will be set to a value from the range as the loop proceeds, and will
advance one step every time the loop hits end until it’s
done:
def index count=13 @result =' 'for i in 1..count@result = @result + i.to_s + " "endend
Of course, like most things Ruby, the for loop has greater powers than just
this. You can use it to iterate over an array:
def index my_array= [5, 4, 3, 2, 1] @result =' 'for i in myArray@result = @result + i.to_s + " "endend
The loop will go through the array to produce “5 4 3 2 1.” You can do even fancier things
with hashes, extracting both the key and the value:
def index
my_hash= { 'one' => 1, 'two' => 2, 'three' => 3, 'four' => 4 }
@result =' '
for key,value in my_hash
@result = @result + "key: " + key + " - value: " + value.to_s + "<br />"
end
endAs always, don’t expect the hash to be reported in any given order. Ruby reserves the right to present hashes however it wants. You’ll see a result something like:
key: three - value: 3 key: two - value: 2 key: one - value: 1 key: four - value: 4
These are a few of the simpler ways to use loops in Ruby. There’s much more to explore.
Ruby offers, and Rails can use, a variety of other structures for passing control through a program:
return, break, next, and redo statements for moving through or
from loops
throw and catch statements for breaking out of
code
Iterators that go beyond loops
raise, rescue, retry, and ensure statements for exceptions
Rails doesn’t allow the use of Ruby’s BEGIN and END statements, however, or its support for
threads.
[2] Sometimes this is called “duck typing” because when Ruby processes information, “if it looks like a duck and quacks like a duck, it’s a duck.”
If you enjoyed this excerpt, buy a copy of Learning Rails .
Copyright © 2009 O'Reilly Media, Inc.