I’d like to think that it offers a unique perspective on developing a full Ruby on Rails tion from scratch in the same or at least, similar manner that people are developingRails applica
Trang 1Ryan Bigg
Yehuda Katz
IN ACTION
Trang 2Rails 3 in Action
Trang 4Rails 3 in Action
RYAN BIGG YEHUDA KATZ
M A N N I N G
SHELTER ISLAND
Trang 5For online information and ordering of this and other Manning books, please visit
www.manning.com The publisher offers discounts on this book when ordered in quantity For more information, please contact
Special Sales Department
Manning Publications Co
20 Baldwin Road
PO Box 261
Shelter Island, NY 11964
Email: orders@manning.com
©2012 by Manning Publications Co All rights reserved
No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by means electronic, mechanical, photocopying, or otherwise, without prior written permission of the publisher
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks Where those designations appear in the book, and Manning
Publications was aware of a trademark claim, the designations have been printed in initial caps
or all caps
Recognizing the importance of preserving what has been written, it is Manning’s policy to have the books we publish printed on acid-free paper, and we exert our best efforts to that end Recognizing also our responsibility to conserve the resources of our planet, Manning booksare printed on paper that is at least 15 percent recycled and processed without the use of elemental chlorine
Manning Publications Co Development editor: Cynthia Kane
20 Baldwin Road Copyeditors: Kevin Hobson, Linda Kern
PO Box 261 Proofreader: Tiffany Taylor
Shelter Island, NY 11964 Typesetter: Dottie Marsico
Cover designer: Marija Tudor
ISBN 978-1-935182-27-6
Printed in the United States of America
1 2 3 4 5 6 7 8 9 10 – MAL – 16 15 14 13 12 11
Trang 6brief contents
1 ■ Ruby on Rails, the framework 1
2 ■ Testing saves your bacon 23
3 ■ Developing a real Rails application 44
5 ■ Nested resources 99
6 ■ Authentication and basic authorization 117
7 ■ Basic access control 136
Trang 8contents
preface xv
acknowledgments xvii
about this book xx
about the authors xxiii
about the cover illustration xxiv
1 Ruby on Rails, the framework 1
1.1 What is Ruby on Rails? 2
Benefits 2 ■ Common terms 3 ■ Rails in the wild 4
1.2 Developing your first application 5
Installing Rails 5 ■ Generating an application 6 ■ Starting the application 6 ■ Scaffolding 7 ■ Migrations 8 ■ Viewing and creating purchases 9 ■ Validations 13 ■ Showing off 14 Routing 15 ■ Updating 16 ■ Deleting 20
2 Testing saves your bacon 23
2.1 Test- and behavior-driven development 24
Trang 93 Developing a real Rails application 44
3.1 Application setup 45
The application story 45 ■ Version control 47 ■ The Gemfile and generators 50 ■ Database configuration 53 ■ Applying a stylesheet 54
6 Authentication and basic authorization 117
6.1 What Devise does 118
Installing Devise 118
Trang 10CONTENTS ix
6.2 User signup 121
6.3 Confirmation link sign-in 122
Testing email 122 ■ Confirming confirmation 123
6.4 Form sign-in 126
6.5 Linking tickets to users 128
Attributing tickets to users 129 ■ We broke something! 131 Fixing the Viewing Tickets feature 132 ■ Fixing the Editing Tickets feature 133 ■ Fixing the Deleting Tickets feature 134
7 Basic access control 136
7.1 Projects can be created only by admins 137
7.2 Adding the admin field to the users table 138
7.3 Restricting actions to admins only 138
Fixing three more broken scenarios 143 ■ Hiding the New Project link 144 ■ Hiding the edit and delete links 146
8.3 Fixing what you broke 172
Fixing Editing Projects 173 ■ Fixing the four failing features 173 ■ One more thing 176 ■ Fixing Signing Up 178
8.4 Blocking access to tickets 183
Locking out the bad guys 183
Trang 118.5 Restricting write access 185
Rewriting a feature 185 ■ Blocking creation 187 ■ What is CanCan? 188 ■ Adding abilities 189
8.6 Restricting update access 190
No updating for you! 191 ■ Authorizing editing 192
8.7 Restricting delete access 193
Enforcing destroy protection 193 ■ Hiding links based on permission 194
9.2 Attaching many files 220
Two more files 221 ■ Using nested attributes 224
9.3 Serving files through a controller 226
Protecting files 227 ■ Showing your assets 228 ■ Public assets 230 ■ Privatizing assets 230
9.4 Using JavaScript 231
JavaScript testing 232 ■ Introducing jQuery 233 ■ Adding more files with JavaScript 234 ■ Responding to an asynchronous request 235 ■ Sending parameters for an asynchronous
10.2 Changing a ticket’s state 252
Creating the State model 253 ■ Selecting states 255 Callbacks 257 ■ Seeding states 259 ■ Fixing creating comments 261
Trang 12CONTENTS xi
10.3 Tracking changes 263
Ch-ch-changes 263 ■ Another c-c-callback 264 ■ Displaying changes 265 ■ Show me the page 266 ■ Automatic escaping saves your bacon 267 ■ Styling states 268
10.4 Managing states 269
Adding additional states 270 ■ Defining a default state 273
10.5 Locking down states 278
Hiding a select box 278 ■ Bestowing changing state permissions 280 ■ Hacking a form 282 ■ Ignoring a parameter 283
11.2 Adding more tags 292
Adding tags through a comment 292 ■ Fixing the CommentsController spec 294
12.1 Sending ticket notifications 313
Automatically watching a ticket 314 ■ Using observers 315 Defining the watchers association 316 ■ Introducing Action Mailer 318 ■ An Action Mailer template 320 ■ Delivering HTML emails 322
Trang 1312.2 Subscribing to updates 325
Testing comment subscription 325 ■ Automatically adding a user
to a watchlist 327 ■ Unsubscribing from ticket notifications 328
13.1 The projects API 349
Your first API 351 ■ Serving an API 354 ■ API authentication 355 ■ Error reporting 356 ■ Serving XML 358 ■ Creating projects 360 ■ Restricting access to only admins 362 ■ A single project 365 ■ No project for you! 368 Updating a project 370 ■ Exterminate! 372
13.2 Beginning the tickets API 374 13.3 Rate limiting 377
One request, two request, three request, four 377 ■ No more, thanks! 379 ■ Back to zero 380
Installing RVM 389 ■ Installing Ruby 390
14.3 Creating a user for the app 391
Key-based authentication 391 ■ Disabling password authentication 393
14.4 The database server 394
Creating a database and user 394 ■ Ident authentication 395
Trang 14CONTENTS xiii
14.5 Deploy away! 395
Deploy keys 396 ■ Configuring Capistrano 397 ■ Setting up the deploy environment 400 ■ Deploying the application 401 Bundling gems 403 ■ Choosing a database 405
16.2 Database query enhancements 444
Eager loading 445 ■ Database indexes 446
16.3 Page and action caching 448
Caching a page 448 ■ Caching an action 451 ■ Cache sweepers 454 ■ Client-side caching 457 ■ Caching page fragments 460
16.4 Background workers 462
17.1 A brief history of engines 469
17.2 Why engines are useful 470
17.3 Brand-new engine 471
Creating an engine 471 ■ The layout of an engine 472 Engine routing 476
Trang 1517.4 Setting up a testing environment 478
Removing Test::Unit 479 ■ Installing RSpec and Capybara 481
17.5 Writing your first engine feature 482
Your first Capybara test 483 ■ Setting up routes 484 ■ The topics controller 485 ■ The index action 485 ■ The new action 488 ■ The create action 489 ■ The show action 490 Showing an association count 492
17.6 Adding more posts to topics 493 17.7 Classes outside your control 497
Engine configuration 497 ■ A fake User model 500 Authenticating topics 501 ■ Adding authorship to topics 505 Post authentication 506 ■ Showing the last post 509
17.8 Releasing as a gem 512 17.9 Integrating with an application 513
18 Rack-based applications 516
18.1 Building Rack applications 517
A basic Rack application 518
18.2 Building bigger Rack applications 522
You’re breaking up 522 ■ Running a combined Rack application 524
18.3 Mounting a Rack application with Rails 525
Mounting Heartbeat 526 ■ Introducing Sinatra 527 The API, by Sinatra 528 ■ Basic error checking 532
Trang 16preface
This book has been through quite the development process! It began in 2008 with
Michael Ivey, Yehuda Katz, and Ezra Zygmuntowicz and was called Merb in Action Since
then it has changed name and hands a couple of times, winding up with people such asJames Cox and the great Mike Gunderloy, the latter of whom is probably most famousfor his work on Factsheet Five and many NET books, not to mention being one of thefounding members of the RailsBridge (http://railsbridge.org) organization
Then, somehow, I became involved with this book
I received an email on a cold April morning in 2010 from Christina Rudloff atManning asking if I would have any interest in joining the project I was exceptionallyexcited! I had been writing short blog posts about Rails for years, and the idea offocusing that effort into writing a book made me extremely happy Long story short:Yehuda Katz liked what he saw on my blog and wanted me to join the project Workingwith Yehuda has been brilliant He’s got to be one of the smartest and most patientpeople I have ever met
Shortly after receiving that initial email from Christina, I talked with another son from Manning, Michael Stephens, first via email and then very late at night overthe phone (we are on different continents) about the project I worked out the initialchapter layout, and I distinctly remember one thing that Michael asked me: “Youknow what you’re getting yourself into, right?” I thought “Sure, I’ve written blog postsbefore, how hard could it be?” and replied in much the same manner How little did
per-I know!
Since then, I have learned a lot about the book-writing process For starters, itinvolves a lot more than just the two people and the publishing company on the front
Trang 17cover It also takes a very long time to write a book This book has been my life for thepast year and a bit I’ve spent many weekends, mornings before work, and eveningsafter work (and way too often, time even in my dreams) writing chapters for this book.I’ve talked about it (perhaps too much) as well It’s become such a running jokeamong people I know that when I’m introduced, they ask, “Do you know he’s writing abook?”
Writing is sometimes easy, but other times it can be a struggle to come up with thing at all There have been bad days, sure, but the good days outnumber those mas-sively The feeling of achievement you get when you finish a chapter, or even a section,
any-is awesome Receiving positive feedback from people has been a huge boon to pleting this book
Now, in 2011, the book is finally done, and what an amazing feeling that is! I’d like
to think that it offers a unique perspective on developing a full Ruby on Rails tion from scratch in the same (or at least, similar) manner that people are developingRails applications at this time It’s also the first book to cover the latest features ofRails found in version 3.1
RYAN BIGG
Trang 18acknowledgments
This has been an amazing process, full of amazing people A large portion of thisbook would not have been possible without the support of my employer, Mikel Lind-saar, and company, RubyX, allowing me to take time off to write the book The sup-port of the community at large has also been enormous in helping me complete thisbook Winning the Ruby Hero award at RailsConf, partially due to my work on thisvery book, was the highlight of my career so far After I won the award, Mikel also pro-vided me with a new laptop at no expense to replace my previous one that was threeyears old Bloody champion!
Of course, a lot of this wouldn’t have been as easy if it wasn’t for the Rails CoreTeam’s valiant efforts on their maintenance of the framework over the years and theirconstant focus on improving people’s lives on an almost daily basis Also there areYehuda Katz, Carl Lerche, and André Arko to thank for their work on an importantpart of developing not only Rails applications, but also Ruby libraries such as Bundlerand Thor These people are my idols, and I love them dearly
Through a Rails-based review system called Twist that I built myself over a singleday, I’ve collected more than 1,200 notes from people from around the world whohave been reviewing the book as I have been writing it A special mention goes to thethree people who’ve left the most notes in Twist: Roy Hacker, Deryl Doucette, andPeter Ley An almost-as-special mention goes to the 33 other people who’ve also leftnotes Without your help, this book wouldn’t be half as brilliant as it is today
Also thanks to Tim McEwan for the ideas for the engines chapter, Chris Darrochfor an initial read-through of the first chapters, and Rob Zolkos for helping with some
Trang 19gnarly ePub Ruby and XLST code And yes, thanks to Andrew Snow for assisting with adifficult moral problem in chapter 16 at Railscamp in June 2011.
In addition to those who’ve been leaving notes in Twist, there are the people atManning First, thanks to Christina Rudloff for the initial contact and Michael Ste-phens for the late-night chats and management of the process Candace Gillhooleyand Nick Chase have also been enormously helpful
Cynthia Kane, my development editor at Manning, is particularly special Her jobwas to tell me when I was doing things wrong, such as not segueing between sections
or making the text flow too fast, and to leave me notes such as “FIGURE!!!” when Ineeded an image to go along with the text Our almost weekly catch-ups were wellworthwhile; it was great always having someone there, prodding me for more contentand talking through the process Marjan Bace, fearless leader of Manning Publica-tions, should also be credited for supporting this project for as long as it has beenaround
The production team at Manning, including Troy Mott, has been great throughoutthis process too The extreme focus they’ve shown in finishing this book is stunning Ialso need to mention the wonderful work by Doug Warren in the final technicalproofing of the book, as well as Manning’s copyeditors, who touched up basicallyevery single paragraph in the book
Special thanks to the reviewers who took time out of their busy schedules to vide feedback on the manuscript at different stages during development Theyinclude Jason Rogers, Craig Smith, Emmanuel Asante, Chad Moone, Dr Jamie P Fin-lay, Dave Nicolette, Grant Oladipo, Jean-Philippe Castro, Americo Savinon, ThomasAthanas, Chris Kelly, Greg Vaughn, Pete Helgren, Joshua R Cronemeyer, Peter Melo,Robby O’Connor, Philip Hallstrom, Curtis Miller, Patrick Peak, Anthony J Topper,Brian Rose, Daniel Bretoi, Wesley Moxam, Jon Agnes, and David Workman
Finally, my friends and family have been amazing throughout my entire life, all theway from my parents—who supported my career choice in Ruby on Rails and techni-cal writing, even though they paid for me to study Network Admin at TAFE and alwaystold me that I should “get out the house more”—to my current housemate, whoaccepts that we don’t see much of each other (or at least I think so) You’re all won-derful people, and I hope now that the book is over I will see more of you I would listyou all here if only it didn’t require this book to be printed in a multivolume series
RYAN BIGG
Rails 3 in Action is a long-time coming To give you some perspective, the book was
originally called Merb in Action, and it managed a perpetual beta through the Merb
merge, the release of Rails 3.0, and is finally ready just in time for Rails 3.1
I can say with confidence that Rails 3 in Action would not exist without the hard,
tireless work of Ryan Bigg It was Ryan’s idea to focus the book around real-world
test-ing from the ground up, and it makes Rails 3 in Action the first book for Rails
practitio-ners that teaches Rails the way professional Rails developers do it
Trang 20ACKNOWLEDGMENTS xix
Since we merged Merb with Rails, I have had the benefit of not insignificant port from friends and family, who helped keep me on course in the long process thateventually delivered Rails 3.0 I want to especially call out Aaron Patterson, José Valim,Santiago Pastorino, and Xavier Noria, who stepped up and brought life back to a com-munity that was starting to show signs of age by the time Rails 2.3 hit the shelves AndCarl Lerche, who helped me keep focus on doing things right, even when it wastempting not to
Finally, I would be remiss if I didn't thank my wife, Leah, who has been there for
me through the amazing trajectory of my development career, through good timesand bad Without her, I would have given up long ago
YEHUDA KATZ
Trang 21about this book
Ruby on Rails is a leading web application framework built on top of the fantasticRuby programming language Both the language and the framework place anextreme emphasis on having a principle of least surprise and getting out of the way ofthe developers using it
Ruby on Rails has been growing at a rapid pace, with large internet companiessuch as Yellow Pages and Groupon using it for their core functionality With the latestrelease of Rails, version 3.1, comes a set of changes that improve the already brilliantframework that has been constructed over the past seven years The fantastic commu-nity around the framework has also been growing at a similar pace
This book is designed to take you through developing a full-featured Rails tion from step one, showing you exactly how professionals in the real world are devel-oping applications right now
applica-Who should read this book
This book is primarily for those who are looking to begin working with the Ruby onRails framework and who have some prior experience with Ruby, although that is notentirely necessary
Later chapters, such as chapter 13, “Designing an API,” chapter 17, “Engines,” andchapter 18, “Rack-based applications,” delve into more advanced topics, so these chap-ters are suitable for people who already have a foundation with Rails and are looking
to expand their skillset a little further
If you’re looking for a book that teaches you the same practices that are used inthe real world, then this is the book you are looking for
Trang 22ABOUT THIS BOOK xxi
Chapter 5 begins an introduction to nested resources, building on top of the tures developed in the previous two chapters
Chapter 6 introduces authentication, requiring users to sign in to the applicationbefore they can perform certain tasks
Chapter 7 builds on the work in chapter 6 by adding new areas of the applicationthat are accessible only to users with a certain flag set in the database You also usenamespaces for the first time
Chapter 8 builds on the basic authorization created in chapter 7, fleshing it outinto something neater and more scalable
In chapter 9, you learn about file uploading using the Paperclip gem In this ter you also learn about testing parts of your application that use JavaScript and aboutCoffeeScript, a neater language that compiles down to JavaScript
Chapter 10 builds not one but two new features for the application, adding theability to comment on a ticket as well as track the ticket’s lifecycle through varyingstates
In chapter 11, you add a feature that lets users assign tags to tickets so they can beeasily grouped You also add a feature to allow users to search for tickets matching acertain state or tag, or both
Chapter 12 begins our foray into dealing with email in a Rails application You’llsee not only how to send email but also how to receive messages and parse them intomeaningful data in your application
Chapter 13 involves creating an API for the project resources in an applicationthat provide other applications with a standardized way to access your application’sdata We also look at token-based authentication and how to create multiple versions
of an API
In chapter 14, you deploy the application to an Ubuntu box and set it up to act like
a normal web server using a RubyGem called Passenger and a web server called nginx
In chapter 15, you create a “nice to have” feature: the ability to sign up or sign inusing either Twitter or GitHub When this is complete, people are no longer required
to provide you with an email and password when they sign up; instead, they can useGitHub and Twitter as authentication providers
Trang 23By chapter 16, your application is all grown up and needs to handle any kind ofperformance issues it encounters We cover basic performance enhancements, such
as pagination, database indexing, and page and fragment caching
Chapter 17 introduces a new feature for Rails 3: engines You develop one of yourown from scratch—a forum system—and then integrate it with the existing application Chapter 18 delves into the depths of Rack, explaining how Rack applications aremade and can be tied into Rails The chapter also explains, and contains examples of,middleware being used in Rails
Code conventions and downloads
Code conventions in the book follow the style of other Manning books in the In Action
series All code in listings and in text appears in a monospaced font like this to rate it from ordinary text In some cases, the original source code has been reformat-ted to fit on the pages In general, the original code was written with page-widthlimitations in mind, but sometimes you may find a slight formatting differencebetween the code in the book and that provided in the source download In a few rarecases, where long lines could not be reformatted without changing their meaning, thebook listings contain line-continuation markers Code annotations accompany many
sepa-of the listings, highlighting important concepts In many cases, numbered bullets link
to explanations that follow in the text
Source code for all the working examples in this book is available for downloadfrom the publisher’s website at www.manning.com/Rails3inAction
Author Online
The purchase of Rails 3 in Action includes free access to a private forum run by
Man-ning Publications where you can make comments about the book, ask technical tions, and receive help from the authors and other users To access and subscribe tothe forum, point your browser to www.manning.com/Rails3inAction, and click theAuthor Online link This page provides information on how to get on the forum onceyou are registered, what kind of help is available, and the rules of conduct in theforum
Manning’s commitment to our readers is to provide a venue where a meaningfuldialogue between individual readers and between readers and the authors can takeplace It’s not a commitment to any specific amount of participation on the part of theauthors, whose contribution to the book’s forum remains voluntary (and unpaid) Wesuggest you try asking the authors some challenging questions, lest their interest stray! The Author Online forum and the archives of previous discussions will be accessi-ble from the publisher’s website as long as the book is in print
Trang 24about the authors
RYAN BIGG has been developing Ruby on Rails since version 1.2 and can be foundhelping out the community by answering questions on IRC or StackOverflow or writ-ing documentation He currently works for a web consultancy based in Sydney calledRubyX
YEHUDA KATZ is well known not only for his work on this third version of Ruby onRails, but also for other web-related projects such as jQuery, Bundler, Merb, andSproutCore He currently works for Strobe in San Francisco as a lead developer on
SproutCore and is the coauthor of Manning’s jQuery in Action, Second Edition.
Trang 25compen-us vividly of how culturally apart the world’s towns and regions were jcompen-ust 200 years ago.Isolated from each other, people spoke different dialects and languages In the streets
or in the countryside, it was easy to identify where they lived and what their trade orstation in life was just by their dress
Dress codes have changed since then and the diversity by region, so rich at thetime, has faded away It is now hard to tell apart the inhabitants of different conti-nents, let alone different towns or regions Perhaps we have traded cultural diversityfor a more varied personal life—certainly for a more varied and fast-paced technolog-ical life
At a time when it is hard to tell one computer book from another, Manning brates the inventiveness and initiative of the computer business with book coversbased on the rich diversity of regional life of two centuries ago, brought back to life byMaréchal’s pictures
Trang 26Ruby on Rails, the framework
Welcome aboard! It’s great to have you with us on this journey through the world ofRuby on Rails Ruby on Rails is known throughout the lands as a powerful webframework that helps developers rapidly build modern web applications In partic-ular, it provides lots of niceties to help you in your quest to develop a full-featuredreal-world application and be happy doing it Great developers are happy develop-ers There’s much more to the Rails world than might appear at first glance, butnot overwhelmingly too much And what a first glance! Oh, you two haven’t met?Well, time for some introductions then!
This chapter covers
Exploring Ruby on Rails
Building the foundations of a Ruby on Rails app
Working with the scaffold generator
Trang 271.1 What is Ruby on Rails?
Ruby on Rails is a framework built on the Ruby language, hence the name Ruby onRails The Ruby language was created back in 1993 by Yukihiro “Matz” Matsumuto ofJapan Ruby was released to the general public in 1995 Since then, it has earned both
a reputation and an enthusiastic following for its clean design, elegant syntax, andwide selection of tools available in the standard library and via a package management
system called RubyGems It also has a worldwide community and many active
contribu-tors constantly improving the language and the ecosystem around it
Ruby on Rails was created in 2004 by David Heinemeier Hansson during the opment of 37signals’ flagship product: Basecamp When Rails was needed for other37signals projects, the team extracted the Rails code from it, crafted the beginnings ofthe framework, and released it as open source under the MIT license.1 Since then,Ruby on Rails has quickly progressed to become one of the leading web developmentframeworks This is in no small part due to the large community surrounding it whoare constantly working on submitting patches to add new features or to fix existingbugs Version 3 of this framework indicates yet another significant milestone in theproject’s history and introduces some new concepts, but won’t leave those alreadyfamiliar with the framework in the dark The latest version of Rails is the primaryfocus of this book
devel-1.1.1 Benefits
Ruby on Rails allows for rapid development of applications by using a concept known
as convention over configuration When you begin writing a Ruby on Rails application,
you run an application generator, which creates a basic skeleton of directories andfiles for your application These files and directories provide categorization for pieces
of your code, such as the app/models directory for containing files that interact withthe database and the public/images directory for images Because all of this is alreadythere for you, you won’t be spending your time configuring the way your application islaid out It’s done for you
How rapidly can you develop a Ruby on Rails application? Take the annual Rails
Rumble event This event aims to bring together small teams of one to four developers
around the world to develop Ruby on Rails2 applications in a 48-hour period UsingRails, these teams can deliver amazing web applications in just two days.3 Anothergreat example of rapid development of a Rails application is the 20-minute blogscreencast recorded by Yehuda Katz.4 This screencast takes you from a no-applicationstate to having a basic blogging and commenting system
Ruby on Rails affords you a level of productivity unheard of in other web works because every Ruby on Rails application starts out the same way The similarity
frame-1 The MIT license: http://en.wikipedia.org/wiki/MIT_License.
2 And now other Ruby-based web frameworks, such as Sinatra.
3 To see an example of what has come out of previous Rails Rumbles, take a look at their alumni archive:
http://r09.railsrumble.com/entries.
4 20-minute blog screencast: http://vimeo.com/10732081.
Trang 28What is Ruby on Rails?
between the applications is so close that the paradigm shift between different Railsapplications is not tremendous If and when you jump between Rails applications, youdon’t have to relearn how it all connects—it’s mostly the same
The core features of Rails are a conglomerate of many different parts called
Rail-ties (when said aloud it rhymes with “bowRail-ties”), such as Active Record, Active Support,
Action Mailer, and Action Pack.5 These different Railties provide a wide range of ods and classes that help you develop your applications They prevent you from per-forming boring, repetitive tasks—such as coding how your application hooks intoyour database—and let you get right down to writing valuable code for your business Ever wished for a built-in way of writing automated tests for your web application?
meth-Ruby on Rails has you covered with Test::Unit, part of meth-Ruby’s standard library It’s
incredibly easy to write automated test code for your application, as you’ll seethroughout this book Test::Unit saves your bacon in the long term, and that’s a fantas-tic thing We touch on Test::Unit in the next chapter before moving on to RSpec andCucumber, two other test frameworks that are preferred over Test::Unit and a littleeasier on the eyes too
In addition to testing frameworks, the Ruby community has produced several quality libraries (called RubyGems, or gems for short) for use in your day-to-day devel-opment with Ruby on Rails Some of these libraries add additional functionality toRuby on Rails; others provide ways to turn alternative markup languages such as Mark-down and Textile into HTML Usually, if you can think it, there’s a gem out there thatwill help you do it
Noticing a common pattern yet? Probably As you can see, Ruby on Rails (and thegreat community surrounding it) provides code that performs the trivial applicationtasks for you, from setting up the foundations of your application to handling thedelivery of email The time you save with all these libraries is immense! And becausethe code is open source, you don’t have to go to a specific vendor to get support Any-body who knows Ruby can help you if you’re stuck
In applications that don’t use MVC, the directory structure and how the differentparts connect to each other is commonly left up to the original developer Generally,
5 Railties share the same version number as Rails, which means when you’re using Rails 3.1, you’re using the 3.1 version of the Railtie This is helpful to know when you upgrade Rails because the version number of the installed Railties should be the same as the version number of Rails.
Trang 29this is a bad idea because different people have different opinions on where thingsshould go In Rails, a specific directory structure makes all developers conform to thesame layout, putting all the major parts of the application inside an app directory.This app directory has three main subdirectories: models, controllers, and views.
Domain logic—how the records in your database are retrieved—is kept in models.
In Rails applications, models define the code that interacts with the database’s tables
to retrieve and set information in them Domain logic also means things such as dations or particular actions to perform on the data
Controllers interact with the models to gather information to send to the view.They call methods on the model classes, which can return single objects representingrows in the database or collections (arrays) of these objects Controllers then makethese objects available to the view through instance variables
Views display the information gathered by the controller, by referencing theinstance variables set there, in a user-friendly manner In Ruby on Rails, this display is
done by default with a templating language known as Embedded Ruby ( ERB) ERBallows you to embed Ruby (hence the name) into any kind of file you wish This tem-plate is then preprocessed on the server side into the output that’s shown to the user The assets, helpers, and mailers directories aren’t part of the MVC paradigm, butthey are important parts of Rails The assets directory is for the static assets of theapplication, such as JavaScript files, images, and Cascading Style Sheets (CSS) for mak-ing the application look pretty We look more closely at this in chapter 3
The helpers directory is a place to put Ruby code (specifically, modules) that vides helper methods for just the views These helper methods can help with complexformatting that would otherwise be messy in the view or is used in more than one place Finally, mailers is a home for the classes of your application that deal with sendingemail In previous versions of Rails, these classes were grouped with models but havesince been given their own home We look at them in chapter 11
pro-REST
MVC in Rails is aided by REST, a routing paradigm Representational State Transfer
(REST ) is the convention for routing in Rails When something adheres to this
conven-tion, it’s said to be REST ful Routing in Rails refers to how requests are routed within
the application itself You benefit greatly by adhering to these conventions, becauseRails provides a lot of functionality around RESTful routing, such as determiningwhere a form can, or will, send to
1.1.3 Rails in the wild
A question sometimes asked by people new to Rails is, “Is Rails ready?” Of course it is!The evidence is stacked mightily in Rails’ favor with websites such as Twitter, YellowPages, and of course Basecamp, serving millions and millions of page requests daily.6
6 Some of the more well-known applications that run on Ruby on Rails can be found at http://rubyonrails.org /applications
Trang 30Developing your first application
If any site is a testament to the power of Ruby on Rails, Twitter is it Even thoughTwitter suffered from scaling problems back in 2008 (due to its massive growth and
other technological problems, not due to Rails), it is now the eleventh most popular
website, according to Alexa, and is exceptionally stable
Another well-known site that runs Ruby on Rails is GitHub, a hosting service forGit repositories This site was launched in February 2008 and is now the leading Gitweb-hosting site GitHub’s massive growth was in part due to the Ruby on Rails com-munity quickly adopting it as their de facto repository hosting site Now GitHub ishome to over a million repositories for just about every programming language on theplanet It’s not exclusive to programming languages either; if it can go in a Git reposi-tory, it can go on GitHub As a matter of fact, this book and its source code are kept onGitHub!
Now that you know what other people have accomplished with this framework,let’s dive into creating your own application
1.2 Developing your first application
We covered the theory behind Rails and showed how quickly and easily you candevelop an application Now it’s your turn to get an application going
rvm install 1.9.2
To use this version of Ruby, you would need to use rvm use 1.9.2 every time you wished
to use it or else set up a rvmrc file in the root of your project, which is explained on theRVM site in great detail Alternatively, you can set this version of Ruby as the defaultwith the command rvm use default 1.9.2, and use rvm use system if you ever want
to swap back to the system-provided Ruby install if you have one
If you’re on Windows, you can’t use RVM and you can’t use a 1.9.* version of Ruby,but that’s okay Rails 3 works with Ruby 1.8 versions of Rails too We would recom-mend the use of the Rails Installer program (http://railsinstaller.org) from EngineYard, or installing the Ruby 1.8.7-p352 binary from ruby-lang.org as an alternative
7 Broken Ubuntu Ruby explained here: http://ryanbigg.com/2010/12/ubuntu-ruby-rvm-rails-and-you/.
Trang 31Next, you need to install the rails gem The following command installs bothRails and its dependencies If you’re using the Rails installer you will not need to runthis command because Rails will already be installed:
gem install rails -v 3.1.0
1.2.2 Generating an application
With Rails now installed, to generate an application, you run the rails command andpass it the new argument and the name of the application you want to generate:
things_i_bought When you run this command, it creates a new directory called
things_i_bought, which is where all your application’s code will go You can call yourapplication anything you wish, but it can’t be given the same name as a reserved word
in Rails For example, you wouldn’t call your application rails because it defines a Rails
constant, which is internal to Rails, and the two constants would clash.
The application that you’re going to generate will be able to record purchases youhave made You can generate it using this command:
rails new things_i_bought
The output from this command may seem a bit overwhelming at first, but rest assured:it’s for your own good All of the directories and files generated here provide thebuilding blocks for your application, and you’ll get to know each of them as we prog-ress For now, let’s get rolling and learn by doing, which is the best way of learning
1.2.3 Starting the application
To get the server running, you must first change into the newly created application’sdirectory and then run these commands to start the application server:
3000 on all network interfaces of this machine.8 To connect to this server, go tohttp://localhost:3000 in your favorite browser You’ll see the “Welcome aboard”page, which is so famous in Rails (see figure 1.1)
If you click About Your Application’s Environment, you’ll find your Ruby, Gems, Ruby on Rails, and Rack versions and other environmental data One of thethings to note here is that the output for Environment is Development Rails provides
Ruby-8 This is what the 0.0.0.0 address represents It is not an actual address, so to speak, and so localhost or 127.0.0.1 should be used.
Trang 32Developing your first application
three environments for running your application: development, test, and production.How your application functions can depend on the environment in which it is run-ning For example, in the development environment, classes are not cached; so if youmake a change to a class when running an application in development mode, youdon’t need to restart the server, but the same change in the production environmentwould require a restart
1.2.4 Scaffolding
To get started with this Rails application, you generate a scaffold Scaffolds in Rails
pro-vide a lot of basic functionality but are generally not used for full-scale developmentbecause you may want something more customized, in which case you’d build it your-self But for this example of what Rails can do, let’s generate a scaffold by running thiscommand:
rails generate scaffold purchase name:string cost:float
When you used the rails command earlier, it generated an entire Rails application.You can use this command inside of an application to generate a specific part of theapplication by passing the generate argument to the rails command, followed bywhat it is you want to generate
Figure 1.1 Welcome aboard!
Trang 33The scaffold command generates a model, a controller, and views based on thename passed after scaffold in this command These are the three important partsneeded for your purchase tracking The model provides a way to interact with a data-base The controller interacts with the model to retrieve and format its informationand defines different actions to perform on this data The views display the informa-tion from the controller in a neat format.
Everything after the name for the scaffold are the fields for the database table and
the attributes for the objects of this scaffold Here you tell Rails that the table for your
purchase scaffold will contain name and cost fields, which are a string and a float.9 To
create this table, the scaffold generator generates what’s known as a migration Let’s
have a look at what migrations are
devel-class CreatePurchases < ActiveRecord::Migration
Inside both of these methods you use database-agnostic commands to create anddrop a table In the up method, you create a table and specify the fields you want in
9 Usually you wouldn’t use a float for storing monetary amounts because it can lead to incorrect-rounding errors Generally, you store the amount in cents as an integer and then do the conversion back to a full dollar amount This example uses a float because it’s easier to not have to define the conversion at this point.
Listing 1.1 db/migrate/[date]_create_purchases.rb
Trang 34Developing your first application
that table by calling methods on the t block variable The string and float methodscreate fields of those particular types on any Rails-compatible database system.10 Youspecified these fields when you used the scaffold command The timestampsmethod is special; it creates two fields called created_at and updated_at, which havetheir values set when records are created and updated automatically by Rails
To run the migration, type this command into the console:
rake db:migrate
This command run the self.up part of this migration Because this is your first timerunning migrations in your Rails application, and because you’re using a SQLite3database, Rails first creates the database in a new file at db/development.sqlite3 andthen creates the purchases table inside that When you run rake db:migrate, itdoesn’t just run the self.up method from the latest migration but runs any migrationthat hasn’t yet been run, allowing you to run multiple migrations sequentially
Your application is, by default, already set up to talk to this new database, so youdon’t need to change anything If you ever want to roll back this migration, you’d userake db:rollback, which rolls back the latest migration by running the self.downmethod of the migration.11
Rails keeps track of the last migration that was run by storing it using this line inthe db/schema.rb file:
ActiveRecord::Schema.define(:version => [timestamp]) do
This version should match the prefix of the migration you just created,12 and Rails usesthis value to know what migration it’s up to The remaining content of this file showsthe combined state of all the migrations to this point This file can be used to restorethe last-known state of your database if you run the rake db:schema:load command With your database set up with a purchases table in it, let’s look at how you canadd rows to it through your application
1.2.6 Viewing and creating purchases
Start your browser now and go to http://
localhost:3000/purchases You’ll see the
scaffolded screen for purchases, as shown in
figure 1.2 No purchases are listed yet, so
let’s add a new purchase by clicking New
Purchase
10 So far, MySQL, PostgreSQL, SQLite3, Oracle, Frontbase, and IBM DB.
11 If you want to roll back more than one migration, use the rake db:rollback STEP=3 command, which rolls back the three most recent migrations.
12 Where [timestamp] in this example is an actual timestamp formatted like YYYYmmddHHMMSS
Figure 1.2 Purchases
Trang 35In figure 1.3, you see two inputs for the fields you generated This page is the result
of the new action from thePurchasesController controller What you see on the pagecomes from the view located at app/views/purchases/new.html.erb, and it looks likethe following listing
<h1>New purchase</h1>
<%= render 'form' %>
<%= link_to 'Back', purchases_path %>
This is an ERB file, which allows you to mix HTML and
Ruby code to generate dynamic pages The beginning of
an ERB tag indicates that the result of the code inside the
tag will be output to the page If you want the code to be
evaluated but not output, you use the <% tag, like this:
<% some_variable = "foo" %>
If you were to use <%= some_variable = "foo" %> here,
the some_variable variable would be set and the value
output to the screen By using <%=, the Ruby code is
eval-uated but not output
The render method, when passed a string as in this example, renders a partial A
partial is a separate template file that you can include in other templates to repeatsimilar code We’ll take a closer look at these in chapter 3
The link_to method generates a link with the text of the first argument (Back)and with an href attribute specified by the second argument (purchases_path),which is simply /purchases
This particular partial is at app/views/purchases/_form.html.erb, and the firsthalf of it looks like the following listing
Listing 1.3 First half of app/views/purchases/_form.html.erb
Figure 1.3 A new purchase
Trang 36Developing your first application
This half is responsible for defining the form by using the form_for helper Theform_for method is passed one argument—an instance variable called @purchase—and with @purchase it generates a form This variable comes from the Purchases-Controller’s new action, which is shown in the following listing
The first line in this action sets up a new @purchase variable by calling the new method
on the Product model, which initializes a new object of this model The variable isthen automatically passed through to the view by Rails
Next in the controller is the respond_to method that defines what formats thisaction responds to Here, the controller responds to the html and xml formats Thehtml method here isn’t given a block and so will render the template from app/views/purchases/new.html.erb, whereas the xml method, which is given a block, will executethe code inside the block and return an XML version of the @purchase object You’ll
be looking at what the html response does from here forward because that is thedefault format requested
So far, all of this functionality is provided by Rails You’ve coded nothing yourself.With the scaffold generator, you get an awful lot for free
Going back to the view, the block for the form_for is defined between its do andthe %> at the end of the file Inside this block, you check the @purchase object for anyerrors by using the @purchase.errors.any? method These errors will come from themodel if the object did not pass the validation requirements set in the model If anyerrors exist, they’re rendered by the content inside this if statement Validation is aconcept covered shortly
The second half of this partial looks like the following listing
Trang 37Here, the f object from the form_for block is used to define
labels and fields for your form At the end of this partial, the
submit method provides a dynamic submit button
Let’s fill in this form now and click the submit button You
should see something similar to figure 1.4
What you see here is the result of your posting: a successful
creation of a Purchase Let’s see how it got there The submit
button posts the data from the form to the create action, which looks like the ing listing
format.html { render :action => "new" }
format.xml { render :xml => @purchase.errors, :status => :unprocessabl e_entity }
end
end
end
Here, you use the Purchase.new you first saw used in the new action But this time you
pass it an argument of params[:purchase] params (short for parameters) is a method
that returns the parameters sent from your form in a Hash-like object When you pass
this params hash into new, Rails sets the attributes13 to the values from the form Inside the respond_to is an if statement that calls @purchase.save This method
validates the record, and if it’s valid, the method saves the record to the database and
returns true
If the return value is true, the action responds by redirecting to the new
@purchase object using the redirect_to method, which takes either a path or anobject that it turns into a path (as seen in this example) The redirect_to methodinterprets what the @purchase object is and determines that the path required ispurchase_path because it’s an object of the Purchase model This path takes you tothe show action for this controller The :notice option passed to the redirect_to sets
up a flash message A flash message is a message that can be displayed on the next
Trang 38Developing your first application
should note here that this doesn’t call the new action/method again14 but only ders the template
You can make the creation of the @purchase object fail by adding a validation.Let’s do that now
Let’s test out these validations by going back to http://localhost:3000/purchases,clicking New Purchase, and clicking Create Purchase You should see the errors shown
in figure 1.5
14 To do that, you call redirect_to new_purchase_path , but that wouldn’t persist the state of the
@purchase object to this new request without some seriously bad hackery By rerendering the template, you can display information about the object if the object is invalid.
Listing 1.7 app/models/purchase.rb
Figure 1.5
Errors on purchase
Trang 39Great! Here, you’re told that Name can’t be blank and that the value you entered forCost isn’t a number Let’s see what happens if you enter foo for the Name field and-100 for the Cost field, and click Create Purchase You should get a different error forthe Cost field now, as shown in figure 1.6.
Good to see! Both of your validations are working now When you change Cost to
100 and click Create Purchase, it should be considered valid by the validations andtake you to the show action Let’s look at what this particular action does now
1.2.8 Showing off
This action displays the content such as shown in figure 1.7
The number at the end of the URL is the unique numerical ID for this purchase Butwhat does it mean? Let’s look at the view for this show action now, as shown in the fol-lowing listing
Trang 40Developing your first application
<%= @purchase.cost %>
</p>
<%= link_to 'Edit', edit_purchase_path(@purchase) %> |
<%= link_to 'Back', purchases_path %>
On the first line is the notice method, which displays the notice set on theredirect_to from the create action After that, field values are displayed in p tags bysimply calling them as methods on your @purchase object This object is defined inyour PurchasesController’s show action, as shown in the following listing
Going back to the view (app/views/purchases/show.html.erb) now, at the end ofthis file you see link_to, which generates a link using the first argument as the textfor it and the second argument as the href for that URL The second argument forlink_to is a method itself: edit_purchase_path This method is provided by amethod call in config/routes.rb, which we now look at
1.2.9 Routing
The config/routes.rb file of every Rails application is where the application routes aredefined in a succinct Ruby syntax The methods used in this file define the pathwaysfrom requests to controllers If you look in your config/routes.rb while ignoring thecommented-out lines for now, you’ll see what’s shown in the following listing
ThingsIBought::Application.routes.draw do
resources :purchases
end
Inside the block for the draw method is the resources method Collections of similar
objects in Rails are referred to as resources This method defines the routes and routing
helpers (such as the edit_purchase_path method) to your purchases resources Look
at table 1.1 for a list of the helpers and their corresponding routes
In this table, :id can be substituted for the ID of a record Each routing helper has
an alternative version that will give you the full URL to the resource Simply use the_url extension rather than _path, and you’ll get a URL such as http://localhost:3000/purchases for purchases_url
Listing 1.9 app/controllers/purchases_controller.rb
Listing 1.10 config/routes.rb