- •Introduction
- •Rails Is Agile
- •Finding Your Way Around
- •Acknowledgments
- •Getting Started
- •Models, Views, and Controllers
- •Installing Rails
- •Installing on Windows
- •Installing on Mac OS X
- •Installing on Unix/Linux
- •Rails and Databases
- •Keeping Up-to-Date
- •Rails and ISPs
- •Creating a New Application
- •Hello, Rails!
- •Linking Pages Together
- •What We Just Did
- •Building an Application
- •The Depot Application
- •Incremental Development
- •What Depot Does
- •Task A: Product Maintenance
- •Iteration A1: Get Something Running
- •Iteration A2: Add a Missing Column
- •Iteration A4: Prettier Listings
- •Task B: Catalog Display
- •Iteration B1: Create the Catalog Listing
- •Iteration B2: Add Page Decorations
- •Task C: Cart Creation
- •Sessions
- •More Tables, More Models
- •Iteration C1: Creating a Cart
- •Iteration C3: Finishing the Cart
- •Task D: Checkout!
- •Iteration D2: Show Cart Contents on Checkout
- •Task E: Shipping
- •Iteration E1: Basic Shipping
- •Task F: Administrivia
- •Iteration F1: Adding Users
- •Iteration F2: Logging In
- •Iteration F3: Limiting Access
- •Finishing Up
- •More Icing on the Cake
- •Task T: Testing
- •Tests Baked Right In
- •Testing Models
- •Testing Controllers
- •Using Mock Objects
- •Test-Driven Development
- •Running Tests with Rake
- •Performance Testing
- •The Rails Framework
- •Rails in Depth
- •Directory Structure
- •Naming Conventions
- •Active Support
- •Logging in Rails
- •Debugging Hints
- •Active Record Basics
- •Tables and Classes
- •Primary Keys and IDs
- •Connecting to the Database
- •Relationships between Tables
- •Transactions
- •More Active Record
- •Acts As
- •Aggregation
- •Single Table Inheritance
- •Validation
- •Callbacks
- •Advanced Attributes
- •Miscellany
- •Action Controller and Rails
- •Context and Dependencies
- •The Basics
- •Routing Requests
- •Action Methods
- •Caching, Part One
- •The Problem with GET Requests
- •Action View
- •Templates
- •Builder templates
- •RHTML Templates
- •Helpers
- •Formatting Helpers
- •Linking to Other Pages and Resources
- •Pagination
- •Form Helpers
- •Layouts and Components
- •Adding New Templating Systems
- •Introducing AJAX
- •The Rails Way
- •Advanced Techniques
- •Action Mailer
- •Sending E-mail
- •Receiving E-mail
- •Testing E-mail
- •Web Services on Rails
- •Dispatching Modes
- •Using Alternate Dispatching
- •Method Invocation Interception
- •Testing Web Services
- •Protocol Clients
- •Securing Your Rails Application
- •SQL Injection
- •Cross-Site Scripting (CSS/XSS)
- •Avoid Session Fixation Attacks
- •Creating Records Directly from Form Parameters
- •Knowing That It Works
- •Deployment and Scaling
- •Picking a Production Platform
- •A Trinity of Environments
- •Iterating in the Wild
- •Maintenance
- •Finding and Dealing with Bottlenecks
- •Case Studies: Rails Running Daily
- •Appendices
- •Introduction to Ruby
- •Ruby Names
- •Regular Expressions
- •Source Code
- •Cross-Reference of Code Samples
- •Resources
- •Index
ACTIVE SUPPOR T 184
The book controller in the content subdirectory would be in the Content module.
class Content::BookController < ApplicationController
# ...
end
The two controllers are therefore kept separate inside your application.
The templates for these controllers appear in subdirectories of app/views. Thus, the view template corresponding to the request
http://my.app/admin/book/edit/1234
will be in the file
app/views/admin/book/edit.rhtml
You’ll be pleased to know that the controller generator understands the concept of controllers in modules and lets you create them with commands such as
myapp> ruby script/generate controller Admin::Book action1 action2 ...
This pattern of controller naming has ramifications when we start generating URLs to link actions together. We’ll talk about this starting on page 287.
13.5 Active Support
Active Support is a set of libraries that are shared by all Rails components. Much of what’s in there is intended for Rails internal use. However, Active Support also extends some of Ruby’s built-in classes in interesting and useful ways. In this section we’ll quickly list the most popular of these extensions.
Extensions to Numbers
Class Fixnum gains the two instance methods even? and odd?.
All numeric objects gain a set of scaling methods.
puts 20.bytes |
#=> 20 |
|
puts 20.kilobytes |
#=> 20480 |
|
puts 20.megabytes |
#=> 20971520 |
|
puts 20.gigabytes |
#=> |
21474836480 |
puts 20.terabytes |
#=> |
21990232555520 |
There are also time-based scaling methods. These convert their receiver into the equivalent number of seconds. The months( ) and years( ) methods are approximations—months are assumed to be 30 days long, years 365 days long.
Prepared exclusively for Rida Al Barazi
Report erratum
ACTIVE SUPPOR T 185
puts 20.minutes |
#=> |
1200 |
puts 20.hours |
#=> |
72000 |
puts 20.days |
#=> |
1728000 |
puts 20.weeks |
#=> |
12096000 |
puts 20.fortnights #=> |
24192000 |
|
puts 20.months |
#=> |
51840000 |
puts 20.years |
#=> |
630720000 |
You can also calculate times relative to Time.now using the methods ago( ) and from_now( ) (or their aliases until( ) and since( ), respectively).
puts Time.now
puts 20.minutes.ago puts 20.hours.from_now puts 20.weeks.from_now puts 20.months.ago
#=> Tue May 10 17:03:43 CDT 2005 #=> Tue May 10 16:43:43 CDT 2005 #=> Wed May 11 13:03:43 CDT 2005 #=> Tue Sep 27 17:03:43 CDT 2005 #=> Thu Sep 18 17:03:43 CDT 2003
How cool is that?
Time Extensions
The Time class gains a number of useful methods, helping you calculate relative times.
now = Time.now puts now
puts now.ago(3600)
puts now.at_beginning_of_day puts now.at_beginning_of_month puts now.at_beginning_of_week
puts now.at_beginning_of_year puts now.at_midnight
puts now.change(:hour => 13) puts now.last_month
puts now.last_year
puts now.midnight puts now.monday
puts now.months_ago(2) puts now.months_since(2) puts now.next_week
#=> Tue May 10 17:15:59 CDT 2005 #=> Tue May 10 16:15:59 CDT 2005 #=> Tue May 10 00:00:00 CDT 2005 #=> Sun May 01 00:00:00 CDT 2005 #=> Mon May 09 00:00:00 CDT 2005
#=> Sat Jan 01 00:00:00 CST 2005 #=> Tue May 10 00:00:00 CDT 2005 #=> Tue May 10 13:00:00 CDT 2005 #=> Sun Apr 10 17:15:59 CDT 2005 #=> Mon May 10 17:15:59 CDT 2004
#=> Tue May 10 00:00:00 CDT 2005 #=> Mon May 09 00:00:00 CDT 2005 #=> Thu Mar 10 17:15:59 CST 2005 #=> Sun Jul 10 17:15:59 CDT 2005 #=> Mon May 16 00:00:00 CDT 2005
puts now.next_year |
#=> |
Wed May 10 17:15:59 CDT 2006 |
|
puts now.seconds_since_midnight #=> |
62159.215938 |
||
puts now.since(7200) |
#=> |
Tue May 10 19:15:59 CDT 2005 |
|
puts now.tomorrow |
#=> |
Wed May 11 |
17:15:59 CDT 2005 |
puts now.years_ago(2) |
#=> |
Sat May 10 |
17:15:59 CDT 2003 |
puts now.years_since(2) |
#=> |
Thu May 10 |
17:15:59 CDT 2007 |
puts now.yesterday |
#=> |
Mon May 09 |
17:15:59 CDT 2005 |
Active Support also includes a TimeZone class. TimeZone objects encapsulate the names and offset of a time zone. The class contains a list of the world’s time zones. See the Active Support RDoc for details.
Prepared exclusively for Rida Al Barazi
Report erratum
LOGGING IN RAILS 186
String Extensions
Active Support adds methods to all strings to support the way the Rails core converts names from singular to plural, lowercase to mixed case, and so on. Of these, two might be useful in the average application.
puts "cat".pluralize |
#=> cats |
puts "cats".pluralize |
#=> cats |
puts "erratum".pluralize |
#=> errata |
puts "cats".singularize |
#=> cat |
puts "errata".singularize |
#=> erratum |
13.6 Logging in Rails
Rails has logging built right into the framework. Or, to be more accurate, Rails exposes a Logger object to all the code in a Rails application.
Logger is a simple logging framework that ships with recent versions of Ruby. (You can get more information by typing ri Logger at a command prompt or by looking in the standard library documentation in Programming Ruby [TH01]). For our purposes, it’s enough to know that we can generate log messages at the warning, info, error, and fatal levels. We can then decide (probably in an environment file) which levels of logging to write to the log files.
logger.warn("I don't think that's a good idea") logger.info("Dave's trying to do something bad") logger.error("Now he's gone and broken it") logger.fatal("I give up")
In a Rails application, these messages are written to a file in the log directory. The file used depends on the environment in which your application is running. A development application will log to log/development.log, an application under test to test.log, and a production app to production.log.
13.7 Debugging Hints
Bugs happen. Even in Rails applications. This section has some hints on tracking them down.
First and foremost, write tests! Rails makes it easy to write both unit tests and functional tests (as we saw in Chapter 12, Task T: Testing, on page 132). Use them, and you’ll find that your bug rate drops way down. You’ll also decrease the likelihood of bugs suddenly appearing in code that you wrote a month ago. Tests are cheap insurance.
Prepared exclusively for Rida Al Barazi
Report erratum
DEBUGGING HINTS 187
Tests tell you whether something works or not, and they help you isolate the code that has a problem. Sometimes, though, the cause isn’t immediately apparent.
If the problem is in a model, you might be able to track it down by running the offending class outside the context of a web application. The scripts/console script lets you bring up part of a Rails application in an irb session, letting you experiment with methods. Here’s a session where we use the console to update the price of a product.
depot> ruby script/console
Loading development environment. irb(main):001:0> pr = Product.find(:first)
=> #<Product:0x248acd0 @attributes={"image_url"=>"/images/sk..." irb(main):002:0> pr.price
=> 29.95
irb(main):003:0> pr.price = 34.95 => 34.95
irb(main):004:0> pr.save => true
Logging and tracing are a great way of understanding the dynamics of complex applications. You’ll find a wealth of information in the development log file. When something unexpected happens, this should probably be the first place you look. It’s also worth inspecting the web server log for anomalies. If you use WEBrick in development, this will be scrolling by on the console you use to issue the script/server command.
You can add your own messages to the log with Logger object described in the previous section. Sometimes the log files are so busy that it’s hard to find the message you added. In those cases, and if you’re using WEBrick, writing to STDERR will cause your message to appear on the WEBrick console, intermixed with the normal WEBrick tracing..
If a page comes up displaying the wrong information, you might want to dump out the objects being passed in from the controller. The debug( ) helper method is good for this. It formats objects nicely and makes sure that their contents are valid HTML.
<h3>Your Order</h3>
<%= debug(@order) %>
<div id="ordersummary">
. . .
</div>
Finally, for those problems that just don’t seem to want to get fixed, you can roll out the big guns and point a debugger at your running application. This is normally available only for applications in the development environment.
Prepared exclusively for Rida Al Barazi
Report erratum
WHAT’S NEXT 188
To use breakpoints:
1.Insert a call to the method breakpoint( ) at the point in your code where you want your application to first stop. You can pass this method a string if you’d like—this becomes an identifying message later.
2.On a convenient console, navigate to your application’s base directory and enter the command
depot> ruby script/breakpointer
No connection to breakpoint service at druby://localhost:42531 (DRb::DRbConnError)
Tries to connect will be made every 2 seconds...
Don’t worry about the No connection message—it just means that your breakpoint hasn’t hit yet.
3.Using a browser, prod your application to make it hit the breakpoint( ) method. When it does, the console where breakpointer is running will burst into life—you’ll be in an irb session, talking to your running web application. You can inspect variables, set values, add other breakpoints, and generally have a good time. When you quit irb, your application will continue running.
By default, breakpoint support uses a local network connection to talk between your application and the breakpointer client. You might be able to use the -s option when you run breakpointer to connect to an application on another machine.
13.8 What’s Next
If you’re looking for information on Active Record, Rails’ object-relational mapping layer, you need the next two chapters. The first of these covers the basics, and the second gets into some of the more esoteric stuff. They’re long chapters—Active Record is the largest component of Rails.
Chapter 16, Action Controller and Rails, looks at Action Controller, the brains behind Rails applications. This is where requests are handled and business logic lives. After that, Chapter 17, Action View, describes how you get from application-level data to browser pages.
But wait (as they say), there’s more! The new style of web-based application makes use of JavaScript and XMLHttpRequest to provide a far more interactive user experience. Chapter 18, The Web, V2.0, tells you how to spice up your applications.
Prepared exclusively for Rida Al Barazi
Report erratum
WHAT’S NEXT 189
Rails can do more than talk to browsers. Chapter 19, Action Mailer, shows you how to send and receive e-mail from a Rails application, and Chapter 20, Web Services on Rails, on page 411, describes how you can let others access your application programmatically using SOAP and XMLRPC.
We leave two of the most important chapters to the end. Chapter 21, Securing Your Rails Application, contains vital information if you want to be able to sleep at night after you expose your application to the big, bad world. And Chapter 22, Deployment and Scaling, contains all the nittygritty details of putting a Rails application into production and scaling it as your user base grows.
Prepared exclusively for Rida Al Barazi
Report erratum