- •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
REGULAR EXPRESSIONS |
476 |
Ruby statement modifiers are a useful shortcut if the body of an if or while statement statement is just a single expression. Simply write the expression, followed
by if or while and the condition.
puts "Danger, Will Robinson" if radiation > 3000
A.8 Regular Expressions
A regular expression is a way of specifying a pattern of characters to be matched in a string. In Ruby, you typically create a regular expression by writing /pattern/ or %r{pattern}.
For example, you could write a pattern that matches a string containing the text Perl or the text Python using the regular expression /Perl|Python/.
The forward slashes delimit the pattern, which consists of the two things we’re matching, separated by a vertical bar (|). This bar character means “either the thing on the right or the thing on the left,” in this case either Perl or Python. You can use parentheses within patterns, just as you can in arithmetic expressions, so you could also have written this pattern as /P(erl|ython)/. Programs typically test strings against regular expressions using the =~ match operator.
if line =~ /P(erl|ython)/
puts "There seems to be a perturbation in the force" end
You can specify repetition within patterns. /ab+c/ matches a string containing an a followed by one or more b’s, followed by a c. Change the plus to an asterisk, and /ab*c/ creates a regular expression that matches one a, zero or more b’s, and one c.
Ruby’s regular expressions are a deep and complex subject; this section barely skims the surface. See the PickAxe book for a full discussion.
A.9 Blocks and Iterators
Code blocks are just chunks of code between braces or between do...end. A common convention is that people use braces for single-line blocks and do/end for multiline blocks.
{ puts "Hello" } |
# this is a block |
do |
### |
club.enroll(person) |
# and so is this |
person.socialize |
# |
end |
### |
Prepared exclusively for Rida Al Barazi
Report erratum
EXCEPTIONS 477
The only place a block can appear is after the call to a method; put the start of the block at the end of the source line containing the method call. For example, in the following code, the block containing puts "Hi" is associated with the call to the method greet( ).
greet { puts "Hi" }
If the method has parameters, they appear before the block.
verbose_greet("Dave", "loyal customer") { puts "Hi" }
A method can invoke an associated block one or more times using the Ruby yield statement. You can think of yield as being something like a method call that calls out to the block associated with the method containing the yield. You can pass values to the block by giving parameters to yield. Within the block, you list the names of the arguments to receive these parameters between vertical bars (|).
Code blocks appear throughout Ruby applications. Often they are used in conjunction with iterators: methods that return successive elements from some kind of collection, such as an array.
animals = %w( ant bee cat dog elk ) |
# |
create an array |
animals.each {|animal| puts animal } |
# |
iterate over the contents |
Each integer N implements a times( ) method, which invokes an associated block N times.
3.times { print "Ho! " } |
#=> Ho! Ho! Ho! |
A.10 Exceptions
Exceptions are objects (of class Exception or its subclasses). The raise method causes an exception to be raised. This interrupts the normal flow through the code. Instead, Ruby searches back through the call stack for code that says it can handle this exception.
Exceptions are handled by wrapping code between begin and end keywords and using rescue clauses to intercept certain classes of exception.
begin
content = load_blog_data(file_name) rescue BlogDataNotFound
STDERR.puts "File #{file_name} not found" rescue BlogDataFormatError
STDERR.puts "Invalid blog data in #{file_name}" rescue Exception => exc
STDERR.puts "General error loading #{file_name}: #{exc.message}" end
Prepared exclusively for Rida Al Barazi
Report erratum
MARSHALING OBJECTS 478
A.11 Marshaling Objects
Ruby can take an object and convert it into a stream of bytes that can
be stored outside the application. This process is called marshaling. This marshaling saved object can later be read by another instance of the application (or
by a totally separate application), and a copy of the originally saved object can be reconstituted.
There are two potential issues when you use marshaling. First, some objects cannot be dumped: if the objects to be dumped include bindings, procedure or method objects, instances of class IO, or singleton objects, or if you try to dump anonymous classes or modules, a TypeError will be raised.
Second, when you load a marshaled object, Ruby needs to know the definition of the class of that object (and of all the objects it contains).
Rails uses marshaling to store session data. If you rely on Rails to dynamically load classes, it is possible that a particular class may not have been defined at the point it reconstitutes session data. For that reason, you’ll use the model declaration in your controller to list all models that are marshaled. This preemptively loads the necessary classes to make marshaling work.
A.12 Interactive Ruby
irb—Interactive Ruby—is the tool of choice for executing Ruby interactively. irb is a Ruby Shell, complete with command-line history, line-editing capabilities, and job control. You run irb from the command line. Once it starts, just type in Ruby code. irb shows you the value of each expression as it evaluates it.
% irb
irb(main):001:0> def sum(n1, n2) irb(main):002:1> n1 + n2 irb(main):003:1> end
=> nil
irb(main):004:0> sum(3, 4) => 7
irb(main):005:0> sum("cat", "dog") => "catdog"
You can run irb on Rails applications, letting you experiment with methods (and sometimes undo damage to your database). However, setting up the full Rails environment is tricky. Rather than do it manually, use the scripts/console wrapper, as shown on page 187.
Prepared exclusively for Rida Al Barazi
Report erratum
RUBY IDIOMS 479
A.13 Ruby Idioms
Ruby is a language that lends itself to idiomatic usage. There are many good resources on the web showing Ruby idioms and Ruby gotchas. Here are just a few.
•http://www.glue.umd.edu/~billtj/ruby.html
•http://www.rubygarden.org/faq
•http://en.wikipedia.org/wiki/Ruby_programming_language
•http://www.zenspider.com/Languages/Ruby/QuickRef.html
This section shows some common Ruby idioms that we use in this book.
methods such as empty! and empty?
Ruby method names can end with an exclamation mark (a bang method) or a question mark (a predicate method). Bang methods normally do something destructive to the receiver. Predicate methods return true or false depending on some condition.
a || b
The expression a || b evaluates a. If it isn’t false or nil, then evaluation stops and the expression returns a. Otherwise, the statement returns b. This is a common way of returning a default value if the first value hasn’t been set.
a ||= b
The assignment statement supports a set of shortcuts: a op= b is the same as a = a op b. This works for most operators.
count += |
1 |
# same as count = count + |
1 |
|
price *= |
discount |
# |
price = price * |
discount |
count ||= 0 |
# |
count = count || 0 |
So, count ||= 0 gives count the value 0 if count doesn’t already have a value.
obj = self.new
(This idiom is somewhat advanced and can be safely skipped.)
Sometimes a class method needs to create an instance of that class.
class Person < ActiveRecord::Base def self.for_dave
Person.new(:name => 'Dave') end
end
This works fine, returning a new Person object. But later on, someone might subclass our class.
Prepared exclusively for Rida Al Barazi
Report erratum
RDOC DOCUMENTATION 480
class Employee < Person
# .. end
dave = Employee.for_dave # returns a Person
The for_dave( ) method was hardwired to return a Person object, so that’s what is returned by Employee.for_dave. Using self.new instead returns a new object of the receiver’s class, Employee.
require File.dirname(__FILE__) + ’/../test_helper’
Ruby’s require method loads an external source file into our application. This is used to include library code and classes that our application relies on. In normal use, Ruby finds these files by searching in a list of directories, the LOAD_PATH.
Sometimes we need to be specific about what file to include. We can do that by giving require a full filesystem path. The problem is, we don’t know what that path will be—our users could install our code anywhere.
Wherever our application ends up getting installed, the relative path between the file doing the requiring and the target file will be the same. Knowing this, we can construct the absolute path to the target by taking the absolute path to the file doing the requiring (available in the special variable __FILE__), stripping out all but the directory name and then appending the relative path to the target file.
A.14 RDoc Documentation
RDoc is a documentation system for Ruby source code. Just like JavaDoc, RDoc takes a bunch of source files and generates HTML documentation, using syntactic information from the source and text in comment blocks. Unlike JavaDoc, RDoc can produce fairly good content even if the source contains no comments. It’s fairly painless to write RDoc documentation as you write the source for your applications. RDoc is described in Chapter 16 of the PickAxe.
RDoc is used to document Ruby’s built-in and standard libraries. Depending on how your Ruby was installed, you might be able to use the ri command to access the documentation.
Prepared exclusively for Rida Al Barazi
Report erratum
|
RDOC DOCUMENTATION |
481 |
dave> ri String.capitalize |
|
|
----------------------------------------------- |
String#capitalize |
|
str.capitalize => new_str |
|
|
----------------------------------------------------------------- |
|
|
Returns a copy of str with the first character converted to |
|
|
uppercase and the remainder to lowercase. |
|
|
"hello".capitalize |
#=> "Hello" |
|
"HELLO".capitalize |
#=> "Hello" |
|
"123ABC".capitalize |
#=> "123abc" |
|
If you used RubyGems to install Rails, you can access the Rails API documentation by running gem_server and then pointing your browser at the URL http://localhost:8808.
The rake appdoc command creates the HTML documentation for a Rails project, leaving it in the doc/app directory.
Prepared exclusively for Rida Al Barazi
Report erratum
Appendix B
Configuration Parameters
As explained on page 180, the various Rails components can be configured by setting options in either the global environment.rb file or in one of the environment-specific files in the config/environments directory.
B.1 Active Record Configuration
ActiveRecord::Base.logger =logger
Accepts a logger object. This is used internally to record database activity. It is also available to applications that want to log activity.
ActiveRecord::Base.primary_key_prefix_type =option
If option is nil, the default primary key column for each table is id. If :table_name, the table name is prepended. Add an underscore between the table name and the id part by setting the option to the value :table_name_with_underscore.
ActiveRecord::Base.table_name_prefix ="prefix"
Prepend the given strings when generating table names. For example, if the model name is User and the prefix string is "myapp-", Rails will look for the table myapp-users. This might be useful if you have to share a database among different applications or if you have to do development and testing in the same database.
ActiveRecord::Base.table_name_suffix ="suffix"
Append the given strings when generating table names.
ActiveRecord::Base.pluralize_table_names = true | false
If false, class names will not be pluralized when creating the corresponding table names.
Prepared exclusively for Rida Al Barazi
ACTION PACK CONFIGURATION 483
ActiveRecord::Base.colorize_logging = true | false
By default, Active Record log messages use ANSI control sequences, which colorize certain lines when viewed using a terminal application that supports these sequences. Set the option to false to remove this colorization.
ActiveRecord::Base.default_timezone = :local | :utc
Set to :utc to have dates and times loaded from and saved to the database treated as UTC.
ActiveRecord::Locking.lock_optimistically = true | false
If false, optimistic locking is disabled. (See Section 14.5, Optimistic Locking, on page 213.)
ActiveRecord::Timestamp.record_timestamps = true | false
Set to false to disable the automatic updating of the columns created_at, created_on, updated_at, and updated_on. This is described on page 267.
ActiveRecord::Errors.default_error_messages =hash
A hash of standard validation failure messages. You can replace these with your own messages, perhaps for internationalization purposes. The default set are
ActiveRecord::Errors.default_error_messages = { :inclusion => "is not included in the list", :exclusion => "is reserved",
:invalid => "is invalid",
:confirmation => "doesn't match confirmation", :accepted => "must be accepted",
:empty => "can't be empty",
:too_long => "is too long (max is %d characters)", :too_short => "is too short (min is %d characters)",
:wrong_length => "is the wrong length (should be %d characters)", :taken => "has already been taken",
:not_a_number => "is not a number",
}
B.2 Action Pack Configuration
ActionController::Base.asset_host =url
Sets the host and/or path of stylesheet and image assets linked using the asset helper tags.
ActionController::Base.asset_host = "http://media.my.url"
ActionController::Base.view_controller_internals = true | false
By default, templates get access to the controller collections request, response, session, and template. Setting this option to false removes this access.
Prepared exclusively for Rida Al Barazi
Report erratum
ACTION PACK CONFIGURATION 484
ActionController::Base.consider_all_requests_local = true | false
Set to false in production to stop users from seeing stack backtraces. This is discussed in more depth in Section 22.3, Handling Errors, on page 450.
ActionController::Base.debug_routes = true | false
If true, gives detailed information when the routing component fails to parse an incoming URL. Turn off for production.
ActionController::Base.logger =logger
Sets the logger used by this controller. The logger object is also available to your application code.
ActionController::Base.template_root =dir
Template files are looked for beneath this directory. Defaults to app/views.
ActionController::Base.template_class =class
Defaults to ActionView::Base. You probably don’t want to change this.
ActionController::Base.ignore_missing_templates = false | true
If true, no error will be raised if a template cannot be found.
ActionController::Base.perform_caching = true | false
Set to false to disable all caching.
ActionController::Base.page_cache_directory =dir
Where cache files are stored. Must be the document root for your web server.
ActionController::Base.page_cache_extension =string
Overrides the default .html extension used for cached files.
ActionController::Base.fragment_cache_store =caching_class
Determines the mechanism used to store cached fragments. Fragment cache storage is discussed on page 369.
ActionView::Base.cache_template_loading = false | true
Turn on to cache the rendering of templates, which improves performance. However, you’ll need to restart the server should you change a template on disk.
ActionView::Base.field_error_proc =proc
This proc is called to wrap a form field that fails validation. The default value is
Proc.new do |html_tag, instance|
%{<div class="fieldWithErrors">#{html_tag}</div>} end
Prepared exclusively for Rida Al Barazi
Report erratum
ACTION MAILER CONFIGURATION 485
B.3 Action Mailer Configuration
These settings are described in Section 19.1, E-mail Configuration, on page 399.
ActionMailer::Base.template_root = directory
ActionMailer::Base.logger = logger object
ActionMailer::Base.server_settings = hash
ActionMailer::Base.raise_delivery_errors = true | false
ActionMailer::Base.delivery_method = :smtp | :sendmail | :test
ActionMailer::Base.perform_deliveries = true | false
ActionMailer::Base.default_charset = "string"
B.4 Test Case Configuration
The following options can be set globally but are more commonly set inside the body of a particular test case.
# Global setting
Test::Unit::TestCase.use_transactional_fixtures = true
# Local setting
class WibbleTest < Test::Unit::TestCase self.use_transactional_fixtures = true
# ...
use_transactional_fixtures = true | false
If true, changes to the database will be rolled back at the end of each test (see Section 12.7, Transactional Fixtures, on page 170).
use_instantiated_fixtures = true | false | :no_instances
Setting this option to false disables the automatic loading of fixture data into an instance variable. Setting it to :no_instances creates the instance variable but does not populate it.
pre_loaded_fixtures = false | true
If true, the test cases assume that fixture data has been loaded into the database prior to the tests running. Use with transactional fixtures to speed up the running of tests.
Prepared exclusively for Rida Al Barazi
Report erratum