Ruby on Rails is a tool for making web applications—and it’s freakishly good at it.. While these are all cool features of Ruby on Rails, the real reason Rails rocks isnot about vocabular
Trang 4Building a Social Networking Website
Michael Hartl
Aurelius Prochazka
Upper Saddle River, NJ • Boston • Indianapolis • San Francisco
New York • Toronto • Montreal • London • Munich • Paris • Madrid
Capetown • Sydney • Tokyo • Singapore • Mexico City
Trang 5“Rails,” “Ruby on Rails,” and the Rails logo are trademarks of David Heinemeier Hansson All rights reserved The authors and publisher have taken care in the preparation of this book, but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions No liability is assumed for incidental or consequential damages in connection with or arising out of the use of the information or programs contained herein.
The publisher offers excellent discounts on this book when ordered in quantity for bulk purchases or special sales, which may include electronic versions and/or custom covers and content particular to your business, training goals, marketing focus, and branding interests For more information, please contact:
U.S Corporate and Government Sales
Visit us on the Web: www.awprofessional.com
Library of Congress Cataloging-in-Publication Data
Copyright c 2008 Pearson Education
All rights reserved Printed in the United States of America This publication is protected by copyright, and permission must be obtained from the publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission
in any form or by any means, electronic, mechanical, photocopying, recording, or likewise For information regarding permissions, write to:
Pearson Education, Inc.
Rights and Contracts Department
75 Arlington Street, Suite 300
Boston, MA 02116
Fax: (617) 848-7047
ISBN 13: 978-0-321-48079-8
ISBN 10: 0-321-48079-1
Text printed in the United States on recycled paper at RR Donnelley in Crawfordsville, Indiana.
First printing, July 2007
Trang 8List of figures xvii
Acknowledgments xxi
Chapter 1 Introduction 1
1.1 Why Rails? 1
1.1.1 Productivity wants to be free 2
1.1.2 This productivity ain’t free 3
1.2 Why this book? 3
1.3 Who should read this book? 4
1.3.1 How to read this book 5
1.3.2 How to watch this book 5
1.4 A couple of Rails stories 5
2.1.1 Setting up your development environment 15
2.1.2 Running withrails 15
2.1.3 Development server 18
vii
Trang 92.2 Our first pages 20
2.4.1 ERb, actions, and instance variables 30
2.4.2 Recap: slicing up a page 32
2.4.9 Finding things for yourself 37
2.5 Developing with style 38
Chapter 3 Modeling users 43
3.1 Creating the User model 43
3.1.1 Setting up the database 43
3.1.2 Migrations and the User model 46
3.1.3 The first user migration 47
3.1.4 Raking the migration 49
3.2 User model validations 51
Trang 10Chapter 4 Registering users 65
4.1 A User controller 65
4.2 User registration: The view 66
4.2.1 The registration view: Appearance 66
4.2.2 Understanding the registration view 70
4.2.3 Registration form refinements 72
4.2.4 Fun with forms—anddebug 75
4.3 User registration: The action 77
4.3.1 Form error messages 82
Chapter 5 Getting started with testing 97
5.1 Our testing philosophy 98
5.2 Test database configuration 98
5.3 Site controller testing 99
5.3.1 A nontrivial test 100
5.3.2 Test overkill? 103
5.4 Registration testing 103
5.4.1 Running functional tests 104
5.4.2 Basic registration tests 104
5.4.3 Testing successful registration 107
5.4.4 Testing unsuccessful registration 108
5.4.5 Running the tests 110
5.4.6 More registration tests? 111
5.5 Basic User model testing 111
5.5.1 Basic validation testing 113
5.6 Detailed User model testing 115
5.6.1 Testing uniqueness 115
5.6.2 Testing screen name length 117
Trang 115.6.3 Detour: “Use the Console, Luke.” 118
5.6.4 Testing password length 120
5.6.5 Testing regexps 122
5.6.6 Running all tests 128
Chapter 6 Logging in and out 131
6.1 Maintaining state with sessions 131
6.1.1 Setting up database sessions 132
6.2 Logging in 134
6.2.1 Tracking login status 134
6.2.2 Registration login 134
6.2.3 Debugging with the session variable 135
6.2.4 Login view and action 138
6.2.5 Testing valid login 142
6.2.6 Testing invalid login 145
6.3 Logging out 146
6.3.1 Testing logout 147
6.3.2 Testing navigation 148
6.4 Protecting pages 150
6.4.1 Protecting pages the stupid way 151
6.4.2 Protecting pages the smart way 152
6.4.3 Testing protection 155
6.5 Friendly URL forwarding 156
6.5.1 Therequestvariable 156
6.5.2 Friendly login forwarding 158
6.5.3 Friendly register forwarding 161
6.6.5 Unduplicated form handling 176
6.6.6 Unduplicated friendly forwarding 177
6.6.7 Sanity check 179
Trang 12Chapter 7 Advanced login 181
7.1 So you say you want to be remembered? 181
7.1.1 A “remember me” box 182
7.1.2 A “remember me” attribute 184
7.1.3 The “remember me” cookie 186
7.2 Actually remembering the user 192
7.2.1 An authorization cookie 193
7.2.2 Remembering that we remembered 195
7.2.3 Updatinglogout 197
7.2.4 A more secure cookie 199
7.2.5 The finished (?) functions 201
7.3 “Remember me” tests 203
7.3.1 Updated login tests 203
7.3.2 Updated logout test 209
7.4 Advanced tests: Integration testing 209
7.4.1 Testing cookie remembering: The first cut 210
7.4.2 Testing the test: A cautionary tale 212
7.4.3 Some reflections on Rails testing 214
7.5 Refactoring redux 215
7.5.1 Refactoring remember 216
7.5.2 Refactoring forget 218
7.5.3 Just two more bits of polish 219
7.5.4 The fully refactored login function 222
7.5.5 Some parting thoughts 223
Chapter 8 Updating user information 225
8.1 A non-stub hub 226
8.2 Updating the email address 226
8.3 Updating password 229
8.3.1 Handling password submissions 233
8.4 Testing user edits 237
8.4.1 Test helpers 237
8.4.2 Testing the edit page 242
8.4.3 An advanced test 243
Trang 138.5 Partials 245
8.5.1 Two simple partials 246
8.5.2 A more advanced partial 247
8.5.3 A wrinkle, then done 249
8.5.4 Updating login and register 250
PART II Building a social network 253
Chapter 9 Personal profiles 255
9.1 A user profile stub 256
9.1.1 Profile URLs 256
9.1.2 Profile controller and actions 258
9.2 User specs 260
9.2.1 Generating the Spec model 260
9.2.2 The Spec model 262
9.2.3 Tying models together 264
9.3 Editing the user specs 266
9.4 Updating the user hub 277
9.4.1 The new hub view 277
9.4.2 A Spec box 280
9.4.3 Named routes and the profile URL 282
9.4.4 The hub main content 285
9.5 Personal FAQ: Interests and personality 288
9.5.1 The FAQ model 288
9.5.2 The FAQ controller 292
9.5.3 Editing the FAQ 293
9.5.4 Adding the FAQ to the hub 294
9.5.5 FAQ tests 298
9.6 Public-facing profile 299
Trang 14Chapter 10 Community 303
10.1 Building a community (controller) 303
10.2 Setting up sample users 304
10.2.1 Collecting the data 305
10.2.2 Loading the data 305
10.3 The community index 308
10.3.1 find’s new trick 309
10.3.2 Theindexaction 311
10.3.3 The alphabetical index 313
10.3.4 Displaying index results 316
11.1.3 Searching withfind _ by _ contents 332
11.1.4 Adding pagination to search 336
11.1.5 An exception to the rule 339
11.2 Testing search 341
11.3 Beginning browsing 343
11.3.1 The browse page 343
11.3.2 Find by A/S/L (hold the L) 345
11.4 Location, location, location 350
11.4.1 A local database of geographical data 351
11.4.2 Using GeoData for location search 352
11.4.3 Location names 355
11.4.4 Adding browse validation 358
11.4.5 The final community home page 363
Chapter 12 Avatars 365
12.1 Preparing for avatar upload 365
12.1.1 Adapting a model 366
Trang 1512.1.2 Avatar upload page 368
12.1.3 An avatar partial 371
12.2 Manipulating avatars 373
12.2.1 ImageMagick andconvert 374
12.2.2 Thesavemethod 377
13.1.3 Linking and delivering the reminder 392
13.1.4 Testing the reminder 396
13.2 Double-blind email system 399
14.1.5 Completing the Friendship model 417
14.1.6 Testing the Friendship model 419
14.2 Friendship requests 420
14.2.1 Friendship request link 420
14.2.2 Controlling the request 423
Trang 16Chapter 15 RESTful blogs 437
15.1 We deserve a REST today 438
15.1.1 REST and CRUD 439
15.1.2 URL modifiers 441
15.1.3 An elephant;in the room 442
15.1.4 Responding to formats and a free API 444
15.2 Scaffolds for a RESTful blog 445
15.2.1 The first RESTful resource 445
15.2.2 Blog posts 447
15.2.3 The Posts controller 450
15.3 Building the real blog 454
15.3.1 Connecting the models 454
15.3.2 Blog and post routing 455
15.3.3 Posts controller, for real 456
15.4.1 Default REST functional tests 474
15.4.2 Two custom tests 476
Chapter 16 Blog comments with Ajax 479
16.1 RESTful comments 479
16.1.1 Comments resource 480
16.1.2 Comment model and associations 481
16.1.3 The Comments controller and a preemptive partial 482
Trang 1716.3.2 Two more effects 497
16.3.3 A cancel button 499
16.3.4 Degrading gracefully 499
16.4 Debugging and testing 501
16.4.1 Another look atnew 502
16.4.2 Testing Ajax withxhr 502
Chapter 17 What next? 505
17.1 Deployment considerations 505
17.1.1 Software and hardware options 506
17.1.2 Running in production mode 506
17.1.3 A minimal production server 508
17.1.4 Scaling 509
17.1.5 Administration basics 511
17.2 More Ruby and Rails 515
Index 517
Trang 182.1 Top-level directory structure 16
2.2 Rails, as a pie chart (Mmm pie.) 17
2.3 Here’s proof that your server is running 19
2.4 Information about the Ruby on Rails environment 19
2.5 Simple representation of the MVC architecture 21
2.6 Tree view of the files we created withgenerate 22
2.7 The default view for the Site controller 24
2.8 Our front page 27
2.9 About Us page 27
2.10 Help page 28
2.11 A navigation bar now appears at the top of each page 33
2.12 The effect of using thelink _ to _ unless _ current. 38
2.13 The main page with CSS defined 41
2.14 The about page with CSS defined 41
2.15 The help page with CSS defined 41
3.1 Users schema as displayed by CocoaMySQL 50
4.1 Registration page 68
4.2 A more stylish registration page 71
4.3 Registration page after submission withfoo,bar, andbaz in the three fields 76
4.4 The development log (with user paramsfoo, bar, baz) 79
4.5 Exception created byraise params[:user].inspect 80
4.6 Errors reported by a blank submission 84
4.7 Pretty error reporting 85
xvii
Trang 194.8 A different set of errors found 86
4.9 Flash notice announcing successful user creation 90
4.10 Rails application documentation 94
6.1 A typical multiple webserver, single database server setup 133
6.2 Session information when registering a new user 136
6.3 Debug links appear at the bottom, separated from the content 138
6.4 Debug information display when both params and session are clicked 139
6.5 Login page 141
6.6 Login-dependent navigation bar 147
6.7 The full request dump withREQUEST _ URIhighlighted 158
6.8 The full request dump withenv _ tablehighlighted 159
6.9 The environment hash displayed separate from the request 160
7.1 The “remember me?” checkbox 182
7.2 The error Rails displays when trying to log infoobar 184
7.3 Debug information shown when blank form is submitted with checkbox unchecked 186
7.4 Debug information shown when a blank form is submitted with the checkbox checked 187
7.5 Viewing cookies on the Safari browser 202
8.1 The logged-in user experience begins to take form 227
8.2 Editing the email address (with error) 228
8.3 Changing the email address tobazquux@example.com 229
8.4 The edit page with password added 232
8.5 The final edit form 233
8.6 Errors generated manually and using thevalid?function 238
8.7 The registration page now handles password confirmation automatically 252
9.1 The basic stub for Foo Bar’s RailsSpace profile 259
9.2 The result of visitinghttp://localhost:3000/profile/foobar2 for nonexistent user “foobar2.” 260
9.3 Editing Foo Bar’s spec 271
9.4 Exposing the date select implementation by way of posting an invalid date (a date that was in the future when this chapter was written) 272
9.5 The updated user hub with user info moved into a sidebar 280
9.6 The updated user hub with spec sidebar 283
9.7 The user hub with the right column starting to fill in 288
Trang 209.8 The FAQ edit page Feel free to change the rows/cols to suit
your style! 295
9.9 The user hub updated with the FAQ 297
9.10 A public-facing profile 302
10.1 The finished community index (shown for the letter H) 308
10.2 The RailsSpace community page with a nicely styled alphabetical index 316
10.3 The final form of the community index 319
10.4 Page after adding style to the results table 321
10.5 Paginated alphabetical listing 324
11.1 The evolving community index page now includes a search form 330
11.2 Search results forq=*, returning unpaginated results for all users 335
11.3 Search results forq=*, returning paginated results for all users 338
11.4 Ferret throws an exception when given an invalid search string 340
11.5 The ferret query parse exception caught and handled 341
11.6 The final browse form 346
11.7 The browse form with some values submitted 346
11.8 Browsing our database by restricting spec parameters 350
11.9 The geographical data in the database 353
11.10 All female RailsSpace users between the ages of 50 and 65 within 250 miles of Caltech 356
11.11 All male RailsSpace users between the ages of 65 and 90 within 250 miles of Caltech 357
11.12 Browse results with city and state lookup 359
11.13 Browsing for “foo” instead of integers 360
11.14 Browse form with a nice description of the errors 363
11.15 The final community page with index, browse, and search 364
12.1 The initial avatar upload page 371
12.2 The user hub with a link to avatar upload 373
12.3 Browsing for an avatar image 379
12.4 The user hub after a successful avatar upload 380
12.5 The error message for an invalid image type 383
12.6 Confirming avatar deletion with JavaScript 384
13.1 The login page with screen name/password reminder 393
13.2 The email reminder form 395
13.3 The email correspondence page with errors 403
13.4 A RailsSpace email sent by Foo Bar (in development mode) 406
Trang 2114.1 A sketch of the database tables needed to model friendships 412
14.2 The two rows for a (potential) friendship between Foo (1) and Baz (2) 413
14.3 A user’s profile with friendship request link and confirmation message 422
14.4 A user’s profile immediately after a friendship request 425
14.5 A friendship request email 425
14.6 The user hub with requested and pending friends 431
14.7 A user profile with friend listing 434
15.1 A hypothetical RESTful Specs resource 440
15.2 Nested resources for RESTful blog posts 448
15.3 Blog post management using the posts index page 461
15.4 The blog post creation page 463
15.5 The default show page 464
15.6 Styled show page 466
15.7 Index page with a couple of blog entries added 466
15.8 The post edit form (with a funky semicolon URL) 468
15.9 The blog on the profile page 471
16.1 Nested resources for RESTful blog comments 485
16.2 The “Add a comment” link becomes the comment form through the magic of Ajax 490
16.3 The form goes away and the comment shows up 492
16.4 Blog post comment with a “delete” link 494
16.5 With the puff effect, a deleted comment grows in size as it fades away 498
17.1 The RailsSpace homepage in a production environment, with no debug links 508
17.2 The local error page for an invalid request 514
17.3 The public error page for file not found errors (404) 514
17.4 The application error page (500) (in this case, a syntax error in theroutes.rbfile) 514
Trang 22Thanks to Debra Williams Cauley for shepherding us through the publishing process.
We would also like to thank our technical reviewers, Francis Hwang and Michael Vanier,for their careful reading and critiques
xxi
Trang 24RailsSpace teaches you Ruby on Rails by developing a real-world application: RailsSpace,
a social networking website aimed at the Rails community itself We take you step bystep, from the virtually static front page, through user registration and authentication,
up to a highly dynamic site with user profiles, image upload, simple blogs, full-text andgeographical search, and a friendship request system Though certainly not intended as
a serious competitor to the social networking heavyweights, RailsSpace is not a toy; it’sdesigned to show how to use Rails to make a web application suitable for deploymentinto a production environment
1.1 Why Rails?
Ruby on Rails is a tool for making web applications—and it’s freakishly good at it Ifyou’re reading this (which, evidently, you are), you’re probably wondering what makesRails so special When you ask this of a programmer who has already fallen in love withRails, maybe he’ll tell you it’s “agile,” and you’ll have to read up on what that means
to coders Or maybe you’ll be bombarded by a list of acronyms like ORM, MVC, orDRY While these are all cool features of Ruby on Rails, the real reason Rails rocks isnot about vocabulary; it’s about the philosophy of efficient design
There’s that word: design It’s a slippery concept, yet unmistakable Good design is
like pornography: You know it when you see it Rails is like very, very good pornography.What makes the design of Rails so good is difficult to pin down, but we’ll do our best
We think the heart of it is free productivity.
1
Trang 251.1.1 Productivity wants to be free
The essence of free productivity is the eerie ability Rails has to anticipate your needs as
a web programmer That’s not very concrete, though, so let’s get a flavor for the freeproductivity Rails provides by looking at a list of examples Not all of these will makesense to you right now, but they should help you develop an intuition for the kinds ofthings Rails is good at
• Ruby: Rails applications, as well as Rails itself, are written in Ruby, a dynamic,
object-oriented programming language Ruby comes out of the Perl tradition, andYukihiro “Matz” Matsumoto, the creator of Ruby, calls it “a better Perl than Perl.”
In our experience, most programmers with exposure to both languages agree We’dadd that, for web programming, embedded Ruby (ERb) is a better PHP than PHP.Being able to tap into the power and elegance of Ruby is a major advantage ofRails
• Mapping of database tables to Ruby objects: There are no messy SQL1 calls inmost Rails applications—instead you’ll find Ruby objects and methods Rails doesthe dirty database work behind the scenes (If, by some chance, you do want toexecute some raw SQL, Rails lets you do that, too.)
• Automatic conversion of data models into HTML and back: There is seamless
integration between the code for modeling objects in your system and the code
to display them to the user This is nowhere clearer than in data validations; forexample, if your data model requires users to put in an email address, but the usersubmits a form without one, Rails can automatically catch the error and put it in avariable for display back to the user
• Built-in support for automated testing of data models and web pages: Rails
makes it easy to write test suites that verify the integrity of your data model and thecorrectness of the pages on your site, allowing you to be confident that changes toyour code will not break your application
• Database-independent creation and alteration of database tables: Rails
migra-tions make it easy to create your data models, make changes to them, and roll them
back if necessary, all in a way that makes it possible to use the same model fordifferent databases
1 SQL, or Structured Query Language, is the language of relational databases.
Trang 261.1.2 This productivity ain’t free
Now that we’ve given a sense of what free productivity is, it’s important to explain whatfree productivity is not Many frameworks come with lots of built-in functionality: aslick administrative interface, fancy role-based authentication and authorization, or theability to write certain applications with virtually no code Even Rails has this capability;
a feature called scaffolding renders certain kinds of form-database interactions trivial—
leading, among other things, to the infamous “15-minute blog engine.”2
That’s not free productivity Built-in authentication or 15-minute blog enginesmight make for great marketing, but between us friends we can probably agree thatany serious software application is going to take more than 15 minutes, no matter howbrilliant the framework Don’t get us wrong; if, by some chance, the application youhave in mind is rendered trivial by some existing framework, by all means use it But
if, as is more likely, you want to build something new, you need a framework that willhelp you when you need it and will get out of your way when you don’t You need atool that will help you realize your vision; a tool flexible enough to change as your visionchanges; a tool that, in the end, mutates into a new framework—one that feels as if itwere custom-made to write your exact application
This is where Rails excels Rails is great at making custom applications—Rails helps you make the application you want You don’t switch to Rails because of the cool message
board or blog software available You switch because the process of creating your owncustom apps is so much easier using Rails
1.2 Why this book?
There’s a tension in any educational book between the two extremes of pure tutorial andpure reference We land firmly on the tutorial side of this spectrum, which has manyadvantages Because our application is real, you get to learn Rails as it is actually used.You’ll see for yourself all the great ways that Rails makes writing web applications easier,from its elegant model-view-controller architecture to the brilliance of embedded Ruby.You also get the advantage of artful repetition: You see the most important ideas themost The result is learning by osmosis
In the process of building RailsSpace, we’ll also see how Rails makes it easy to writeautomated tests to make sure our application does what we wanted it to do Because ofour tutorial approach, we will be able to develop the tests incrementally in parallel with
2
Trang 27the application, just as you do (or should do) in real life As our application evolves,you’ll see how great having a test suite is: Whenever we modify a feature or add a newone, we can run the tests to make sure that we haven’t broken some other part of theapplication.
Of course, while good for learning, a tutorial approach is not as good for looking
things up As a counterbalance to RailsSpace, we recommend Agile Web Development with Rails by Dave Thomas and David Heinemeier Hansson (from Pragmatic Programmers), the original introduction to Rails AWDwR contains a wealth of reference material
documenting most aspects of the Rails framework For learning Ruby we recommend
Programming Ruby, Second Edition, by Dave Thomas et al (Pragmatic Programmers), and The Ruby Way, Second Edition, by Hal Fulton (Addison-Wesley).
1.3 Who should read this book?
Since you’re reading this, the chances are good that you should read this book RailsSpace
is an introductory book, so we don’t assume any knowledge of the Ruby programminglanguage or of the Rails framework Of course, any previous exposure to either will bebeneficial Even if you have some prior experience with Rails, we hope you can learnsomething from our book, especially since we use several features (such as migrations,form generators, REST, and Ajax support) introduced in the more recent releases of Rails
To get the most out of RailsSpace, you should probably know at least one
program-ming language, and familiarity with object-oriented programprogram-ming would be especiallyhelpful Java is probably sufficient background,3and it’s even better if you are familiarwith a dynamically typed language such as Perl, Python, or PHP (or Ruby!) It would beespecially good if you’ve used one of these languages to make dynamic websites Someexposure to JavaScript and Cascading Style Sheets (CSS) would also be good At thevery least, you should be familiar with making static websites using HTML Finally, weassume a certain level of computer sophistication, so that when we say “Go downloadMySQL and install it” you’re confident that (given enough time and coffee) you canprobably do it, even if you’ve never installed a database before
All of these supposed prerequisites are really beside the point, though By far themost important factor is your enthusiasm for learning how to make web applicationswith Rails If you’re excited about putting something cool on the web, this book is foryou, no matter what your background is
3 If Java is the only programming language you know, you might get tripped up by the lack of static typing in Ruby If you find yourself freaking out, just take a deep breath and try to have faith that dynamic typing works.
Trang 281.3.1 How to read this book
RailsSpace is designed to be read from start to finish, and you’ll get the most out of it if
you code along with us, but we’ve designed the book to be instructive and interestingeven if you’re not sitting in front of the computer Also, it’s important to be patient Ifyou don’t get something right away, keep pressing forward, and give the ideas a little time
to sink in You’ll be amazed at how something that confuses you at the beginning of achapter will seem trivial by the end You’re training your personal neural network how torecognize Ruby on Rails patterns, and there’s no substitute for practice and perseverance
1.3.2 How to watch this book
The accompanying website for this book can be found at
http://RailsSpace.com/book
There you’ll find errata, sample data, and downloadable source code for RailsSpace You’ll
also find links to screencasts for each chapter—narrated movies of the book’s source codecoming to life
1.4 A couple of Rails stories
We’ve given you a bunch of reasons why Rails rocks, but there’s no substitute for acouple of good, old-fashioned testimonials These are our personal roads to Rails
1.4.1 Aure
Way back in 1994 some friends and I in the Graduate Aeronautical Laboratories atCaltech discovered that we had a department webserver that would serve our owncontent at/ ∼user name/URLs We started out by competing with each other for hitsand instead of personal sites we put up content about our favorite musicians and airplanes.One of us was the teaching assistant for the lab and had control of the∼ta account
We rechristened the initials to stand for “The Asylum” and instead of competing, wepooled our resources to build a crazy place on the web where anyone could log on andcontribute content Some of the apps we created were a public bookmarks repository(precursor to del.icio.us), a public writing forum (precursor to wikis), and a web-basedLite-Brite emulator and gallery (sort of a primitive single-celled ancestor of Flickr!)
We gained a lot of attention for these sites and soon film studios and record companieswere calling the lab tracking us down to hire us to build dynamic websites for them
It was certainly awkward to get phone calls from Universal Pictures while your Ph.D
Trang 29thesis advisor was in the lab, so we started a business and opened an office with a phonenumber of its very own.
We spent a few years building custom websites in Perl/CGI while getting our degrees(which we all managed to do; take that you Yahoo! millionnaire Stanford dropouts!).Slowly the stress of building websites from scratch in Perl wore us out and the companydisbanded I looked back at the websites and realized that many of them were verysimilar, so I began offering standard web components to my clients Meanwhile, PhilipGreenspun was running Photo.net and getting many requests from people wantingthe code that the site ran on Philip assembled his friends to beef up the Photo.netcode and together we founded ArsDigita and open-sourced our code as ACS (ArsDigitaCommunity System), comprised of standard web components and written mostly inTcl We used ACS to get exposure among poor developers, which led us to be found
by rich companies who wanted customizations to the toolkit Unfortunately, venturecapitalists also eyed ArsDigita and once we accepted their money they also had influence;you can read about what happened after that on fuckedcompany.com
Even with ArsDigita gone from the landscape, the toolkit lived on as “OpenACS”
at openacs.org But, as an independent contractor, could I really convince my clientsthat a toolkit started by a defunct company was definitely a long-term solution? Also, Iwas pretty sick and tired of programming in Tcl, so I turned to the prettiest language Iknew—Python That pretty much meant using Zope, and at first Zope was awesome.Indeed, there are still some applications for which Zope is a great choice But Zope hasmany annoyances as well, and my clients yearned for standard version control, filesystemaccess, and better relational database support
One of my favorite ex-employees was now working for Caltech and one day sent me
an email about some emerging frameworks she was considering instead of Zope for hernext project Django and Ruby on Rails were on her list, and after a few hours of research
I knew Zope was history Initially I leaned toward Django because it was in Python, butRuby on Rails was a bit further along, and it had one thing that Django will never have—David Heinemeier Hansson, the creator of Rails From my experience with ArsDigitaand Philip Greenspun I knew the importance of having a compelling, intelligent, andopinionated central figure representing the framework Back then, and through the time
of this writing, DHH has prescribed the philosophy of what Rails is and what it is not.While DHH is its “creator,” Rails clearly is the product of the evolution of webapplication development Here’s what struck me about Rails:
• Ruby, mostly: Web application development always requires some mastery of many
fields You’re going to have to know at least a little about templating languages,
Trang 30database access, and procedural programming But there’s no denying it takes energy
to constantly switch back and forth between languages, especially when languagesmix within one file Rails minimizes this—templating language: Ruby; databaseaccess: Ruby (mostly); procedural programming: Ruby (duh)
• Data modeling, improved: The old way I started a project was to brainstorm
ev-erything that might be needed and write a data model in SQL that would hold thefinal state of the data Then I would have to write the code to populate the databasetables and write the error detection to prevent bad data from going into the database.With Rails migrations, I can now incrementally augment the data model, and withvalidations I write rules that almost automatically show up in my web application
as error reports Also, migrations are database agnostic, so I don’t have to write anew SQL file for the various available databases
Oh, and there are many more things I have learned about Rails that I love, butfrankly, you don’t need a long list of great things about Rails to know it’s for you Infact, if you need a long list, then maybe you’re not convinced It’s like when I bought
my 2001 Nissan Frontier truck: It could carry my dog, it was fast, and it looks like aspaceship—sold!
With Ruby on Rails I can offer clients sites that are completely customized for theirneeds while still being fun for me to program in Everyone is happy!
1.4.2 Michael
When I was at Caltech for graduate school, my friend Sumit Daftuar and I ran a localNCAA basketball tournament pool, which initially involved a small but important webcomponent Sumit used a simple Perl script to generate the results after each round
of the tournament, which got posted to a website Even though it was ridiculouslysimple, people loved it In 2001 I decided to take the next step by using PHP to write
a full web interface for our pool, complete with bracket entry and scoring reports Ireasoned that this would force me to learn web development, and, several 20-hour dayslater, it did
PHP seemed great at first, but as the size of my projects grew, PHP became ingly cumbersome After graduating, Sumit and I started a company that ran uniqueweekly fantasy sports games and produced an improved version of our NCAA site calledBracketManager I didn’t want to use PHP for the company sites, so I started lookingaround for something new I had learned Perl and Python in the course of my Ph.D.research, and I looked at several frameworks in those languages
Trang 31increas-I eventually settled on Zope, which is written in Python, even though it wasn’tparticularly well-suited for our primary purpose—namely, writing a large custom webapplication Like many frameworks, Zope uses a watered-down template language togenerate HTML, but many web applications (including ours) generate such complicatedHTML that they really need a full-strength language under the hood We ended upwriting most of our HTML in pure Python and coupling it to Zope using “externalmethods,” which got the job done but were rather cumbersome I also found Zope’sdocumentation to be spotty at best, due in large part to Zope’s relatively small user base.Finally, Zope has weak support for relational databases; in particular, the Zope MySQLdatabase adapter provided no support for generating the often comically verbose queriesrequired by SQL, forcing me to write a custom MySQL library in Python.
Despite all these problems with Zope, Python is so much better than PHP that it wasworth the trouble Unfortunately, our fantasy games never reached a critical mass, andthe final straw came when the NFL Players Association started (and the MLB PlayersAssociation threatened) to sue any fantasy sports companies using the players’ nameswithout a license Unable to get licenses, we decided to shut the company down Thiswas unfortunate, but it did give me a chance finally to abandon my Zope codebase andtake a look at a new framework I had been reading about called Ruby on Rails I had amental checklist of things I needed in a web development framework, and I was curious
to see if Rails might meet those needs
During all this time, I had kept in touch with Aure Prochazka, a tall, quiet, looking guy I had met while singing in the Caltech Glee Club He seemed to know alot about web development, so back in my PHP days I talked with him a bit about thatlanguage He’d looked at it a little, he said, and it seemed fine I talked to him maybe
scruffy-a yescruffy-ar lscruffy-ater, scruffy-and he told me thscruffy-at he hscruffy-ad tscruffy-aken scruffy-a good look scruffy-at PHP scruffy-and decided thscruffy-at itsucked; he had gone with Python and Zope instead I replied that I had also switched
to Zope After another year or so, I mentioned that I had become dissatisfied with Zopeand was looking at Ruby on Rails He replied that he had recently switched from Zope
to Rails, and loved his new framework
In an effort to jump-start my Rails education, I took a Pragmatic Studio courseoffered by Dave Thomas and Mike Clark, spending my own hard-earned cash despiteMike’s best efforts to convince me not to take the class I’m glad that Mike was not morepersuasive, because I sat in amazement as one item after another on my mental list gotchecked off:
• An elegant programming language with flexible data structures and powerful
abstractions: check
Trang 32• Good documentation, with a relatively large (and rapidly growing) user base: check
• Mature relational database support, with a good object-relational mapping library:
be interested in submitting a proposal to write a book on Rails with him, I leapt at theopportunity
There’s no turning back now And there’s no stopping Ruby on Rails
Trang 34P ART I
Foundations
11
Trang 36Getting started
It’s time to start building RailsSpace, a social networking website for Ruby on Railsenthusiasts (and whoever else shows up) Eventually, RailsSpace will have many of thefeatures associated with popular social networks such as Facebook and MySpace, withsearchable user profiles, an email system, and friends lists The first part of the booklays a foundation by developing a system for registration, login, and authentication.This system is essential for our purposes, but it’s also needed for virtually any user-basedweb application In the second part, we’ll build a social network on this foundation Ofcourse, in the process of making this specific type of application, we’ll develop manygeneral techniques useful for building other kinds of websites as well
In this chapter, we’ll get started with the application by making the front page of oursite, together with a couple of other static pages Much of what we do in this chapter could
be done quite easily with plain HTML files, but even in this extremely simple case Railsstill proves surprisingly convenient It also makes for a gentle introduction to some of thecore concepts behind Rails, including embedded Ruby and the model-view-controllerarchitecture
Trang 37RailsSpace are from the Macintosh platform, but we can report from personal
experi-ence that Rails is unambiguously cross-platform; you can build great Rails applications
no matter which operating system you choose.
We bet that many of you have, in your excitement, already installed Rails, but if youhaven’t (or if you’re using an older version1) you should do that now Once you’ve chosen
a platform (see the sidebar “Choosing a platform”), head over to the Ruby on Rails load page (http://www.rubyonrails.org/down) for instructions on how to installRails There are many different ways to get rolling with Rails; here is one basic sequence:
and install with
$ /configure; make; sudo make install
If you don’t have sudo2 enabled, you’ll have to log in as root for the finalstep:
$ /configure
$ make
$ su
# make install
• OS X: There are some issues with the Ruby that ships with OS X 10.4, so you
might want to take a look at this:3http://hivelogic.com/articles/2005/ 12/01/ruby rails lighttpd mysql tiger
2 Install RubyGems, the standard Ruby package manager
• Windows: Download the first RubyGems.zipfile fromhttp://rubyforge org/frs/?group id=126and unzip it, extracting the files to a directory on your
1 For this book, you should have Ruby 1.8.5 or later and Rails 1.2 or later.
2 How do you do the sudo that you do so well?
3 Also consider Locomotive ( http://locomotive.sourceforge.net/ ), a prepackaged Rails bundle for
OS X.
Trang 38local disk Using a command prompt (DOS window), navigate to the directorywhere you extracted the files and run
> ruby setup.rb
• Linux and OS X: Download the first RubyGems .tgz file from http:// rubyforge.org/frs/?group id=126, extract it, and run
$ ruby setup.rb
inside the source directory
3 Install Rails at the command line:4
> gem install rails include-dependencies
Now go get a cup of coffee while Rails and all of its associated files are automagicallyinstalled.5
2.1.1 Setting up your development environment
Your specific development environment will depend somewhat on the platform youchoose, but since Rails applications are written in Ruby, at the very least you’ll need atext editor for writing source code As we’ll see, Rails projects have a lot of different filesand directories, so it’s useful to have an editor or integrated development environment(IDE) able to navigate the directory tree and switch between files quickly
We particularly recommend RadRails,6a free (as in beer and speech) cross-platformRails IDE based on Eclipse (which will be familiar to many Java developers out there).For Rails developers working on OS X, the most popular choice seems to be TextMate,7
a text editor with lots of nice Rails macros and good directory navigation.8
2.1.2 Running with rails
Now that you’ve installed Rails, it’s time to get started with RailsSpace Rails comes with
a program called (appropriately enough) rails, which automatically creates a bunch
4Throughout the rest of RailsSpace, we’ll use> to indicate the prompt in a cross-platform manner; for Windows users, this will be the > in a command prompt (DOS) window, while for Mac OS X and Linux users, it will be the $ in a terminal window.
5 If Rails is already installed, run gem update rails include-dependencies and gem update system
to update your installation.
6http://www.radrails.org/
7http://macromates.com/
8 Lamentably, TextMate is free in neither the beer nor the speech senses of the term.
Trang 39Figure 2.1 Top-level directory structure.
of files and directories to get you started with a new project For a site with a namelike RailsSpace (written in CamelCase), the Rails convention is to create a project withthe corresponding name in underscore format (so we would use camel case for projectCamelCase); in our case that means makingrails space:
> rails rails_space
Therailscommand creates lots of files and folders, which comprise a skeleton ofthe project.9Let’s take a look at it in our file browser (Figure 2.1) One of the great thingsabout Rails applications is that they all share this common directory structure (depicted as
a pie chart in Figure 2.2) It may look a little overwhelming at first, but once you’ve spent
a little time navigating the Rails directory tree it will sink in fast We’ve found that havingthe directory structure decided for us eliminates a lot of headaches since we don’t have tospend any time agonizing about what to call our directories or where to put our new files
Importing projects into RadRails
Here’s how to import a Rails project into RadRails:
1 Go to File -> New -> Rails -> Rails Project and click Next
2 Uncheck the Generate Rails application skeleton and Create
a WEBrick server boxes
9 If you are using RadRails, you should import the Rails project at this point (see the sidebar “Importing projects into RadRails”).
Trang 40controllers helpers
models views
app
images
javascripts
stylesheets public
tasks
lib environments
Figure 2.2 Rails, as a pie chart (Mmm pie.)
3 Edit the default location if it is not the parent directory of your Rails project
(you will have to uncheck the box next to Use default location to do this)
4 Enter the name of your project (rails space in this case) in the box and
click Finish
An alternative to this is to skip the original rails rails space command and then follow the steps above without unchecking Generate Rails application skeleton In this case RadRails will run the rails command automatically.
In case it’s not self-explanatory, we should note that all of the directories in this bookwill be relative to the base directory created by therailscommand For example, if your