Learn Ruby On Rails - Book Two
Learn Ruby On Rails - Book Two
org
2
Learn Ruby on Rails: Book Two
Version 4.2.0, 2 August 2017
Daniel Kehoe
www.dbooks.org
ii
Contents
2 Introduction 3
Is It for You? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
What To Expect . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
About Book One . . . . . . . . . . . . . . . . . . . . . . . . 4
What’s in This Book . . . . . . . . . . . . . . . . . . . . . . 5
A Warning About Links . . . . . . . . . . . . . . . . . . . . . 5
What Comes Next . . . . . . . . . . . . . . . . . . . . . . . . 5
Staying In Touch . . . . . . . . . . . . . . . . . . . . . . . . 6
A Note to Reviewers and Teachers . . . . . . . . . . . . . . . 6
Using the Book in the Classroom . . . . . . . . . . . . . . . . 7
Let’s Get Started . . . . . . . . . . . . . . . . . . . . . . . . 7
iii
www.dbooks.org
iv CONTENTS
Example Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Version Check . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Getting Help With the Book . . . . . . . . . . . . . . . . . . . . . 10
Getting Help With Rails . . . . . . . . . . . . . . . . . . . . . . . . 11
Video Option . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Where To Go For Help? . . . . . . . . . . . . . . . . . . . . . 11
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
RailsGuides . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Cheatsheets . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
API Documentation . . . . . . . . . . . . . . . . . . . . . . . 13
Meetups, Hack Nights, and Workshops . . . . . . . . . . . . . . . . 13
Pair Programming . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Pairing With a Mentor . . . . . . . . . . . . . . . . . . . . . . . . . 15
Code Review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Staying Up-to-Date . . . . . . . . . . . . . . . . . . . . . . . . . . 16
5 Get Started 23
Text Editor and Terminal Applications . . . . . . . . . . . . . . . . 23
Copying and Pasting Code . . . . . . . . . . . . . . . . . . . . . . 24
CONTENTS v
Your Computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Hosted Computing . . . . . . . . . . . . . . . . . . . . . . . 26
Try the Terminal . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Installing Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
MacOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Ubuntu Linux . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Hosted Computing . . . . . . . . . . . . . . . . . . . . . . . 28
Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Your Workspace . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Video Option . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Understanding Version Numbers . . . . . . . . . . . . . . . . . . . 30
Ruby and Rails Version Check . . . . . . . . . . . . . . . . . . . . 31
RVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Project-Specific Gemset . . . . . . . . . . . . . . . . . . . . . . . . 35
www.dbooks.org
vi CONTENTS
Git Log . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Repositories . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Pushing to GitHub . . . . . . . . . . . . . . . . . . . . . . . 68
The README . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
9 Gems 73
Videos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
RubyGems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Rails Gems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Gems for a Rails Default Application . . . . . . . . . . . . . . . . . 76
Where Do Gems Live? . . . . . . . . . . . . . . . . . . . . . . . . 77
Gemfile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Gemfile for a Rails Default Application . . . . . . . . . . . . . . . 80
Adding Gems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
About the Rails Version . . . . . . . . . . . . . . . . . . . . . . . . 85
Install the Gems . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . 86
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
10 Configure 89
Configuration Security . . . . . . . . . . . . . . . . . . . . . . . . 89
Videos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
About Environment Variables . . . . . . . . . . . . . . . . . . . . . 90
Viewing Hidden Files . . . . . . . . . . . . . . . . . . . . . . . . . 91
Set Environment Variables . . . . . . . . . . . . . . . . . . . . . . 93
www.dbooks.org
viii CONTENTS
SendGrid . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
MailChimp . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Owner Email . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Restart the Terminal Session . . . . . . . . . . . . . . . . . . 95
Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . 95
The Secrets File . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Domain Name . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Securing the Secrets File . . . . . . . . . . . . . . . . . . . . 97
Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . 98
Secret Key Base . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Configure Email . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
Connect to an Email Server . . . . . . . . . . . . . . . . . . . 100
Perform Deliveries in Development . . . . . . . . . . . . . . 102
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
14 Troubleshoot 139
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
www.dbooks.org
x CONTENTS
Houses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
Vehicles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
Cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
Limitations of Metaphors . . . . . . . . . . . . . . . . . . . . 164
Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Dot Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Question and Exclamation Methods . . . . . . . . . . . . . . 169
Initialize Method . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Method Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Symbol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
Instance Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
Instance Variables in Rails . . . . . . . . . . . . . . . . . . . 173
Double Bar Equals Operator . . . . . . . . . . . . . . . . . . . . . 174
Conditional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Ternary Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
Interpolation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
Access Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
Hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Iterator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
www.dbooks.org
xii CONTENTS
Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Rails and More Keywords . . . . . . . . . . . . . . . . . . . . . . . 183
More Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
Collaborative Learning . . . . . . . . . . . . . . . . . . . . . 184
Online Tutorials . . . . . . . . . . . . . . . . . . . . . . . . . 184
Books . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Newsletters . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Screencasts . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
www.dbooks.org
xiv CONTENTS
www.dbooks.org
xvi CONTENTS
22 Deploy 301
Heroku Costs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
Test the Application . . . . . . . . . . . . . . . . . . . . . . . . . . 303
Preparing for Heroku . . . . . . . . . . . . . . . . . . . . . . . . . 304
Gemfile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
Asset Pipeline in Production . . . . . . . . . . . . . . . . . . 306
Option to Ban Spiders . . . . . . . . . . . . . . . . . . . . . . 307
Humans.txt . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
Sign Up for a Heroku Account . . . . . . . . . . . . . . . . . . . . 308
Heroku Toolbelt . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
Heroku Create . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
Enable Email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
www.dbooks.org
xviii CONTENTS
23 Analytics 317
Segment.com . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318
Accounts You Will Need . . . . . . . . . . . . . . . . . . . . . . . 318
Installing the JavaScript Library . . . . . . . . . . . . . . . . . . . 319
Replace the Write Key . . . . . . . . . . . . . . . . . . . . . . . . 322
Add Integration Code . . . . . . . . . . . . . . . . . . . . . . . . . 322
Page View Tracking with Turbolinks . . . . . . . . . . . . . . . . . 323
Event Tracking . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . 325
Segment.com Integrations . . . . . . . . . . . . . . . . . . . . . . . 325
Deploy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
Improving the User Experience . . . . . . . . . . . . . . . . . . . . 327
Conversion Tracking . . . . . . . . . . . . . . . . . . . . . . . . . 327
Enjoy What You’ve Achieved . . . . . . . . . . . . . . . . . . . . . 328
24 Testing 331
Why Test? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331
CONTENTS xix
www.dbooks.org
xx CONTENTS
www.dbooks.org
xxii CONTENTS
Version Check
If you have the PDF, ePub, or Mobi versions of the book, check the title page
for the version number and look on the webpage for the learn-rails GitHub
repository to make sure you have the newest version of the book.
I suggest to use the online edition as you build the tutorial application. It is
always up to date.
www.dbooks.org
2 CHAPTER 1. VERSION CHECK, VIDEOS, AND MORE
The videos are a great introduction to Rails. With the videos and the advanced
tutorials, I promise there is no better way to learn Rails.
Chapter 2
Introduction
Welcome. This is Book Two in my Ruby on Rails book series. It is written for
Rails 5.1.
In this book, you’ll build a working web application so you’ll gain hands-on
experience. Along the way, you’ll practice techniques used by professional
Rails developers. And I’ll help you understand why Rails is a popular choice
for web development.
Read Book One to get the big picture that’s missing from other tutorials. Read
it anywhere, on your phone or tablet. It introduces key concepts so you’ll have
a solid foundation for continued study. You can start this book before you finish
Book One.
This book (Book Two) is for hands-on learning so you’ll need your computer
to follow this tutorial.
In this book, I also provide links to videos. You can get the videos along with
advanced tutorials at the tutorials.railsapps.org site.
www.dbooks.org
4 CHAPTER 2. INTRODUCTION
Is It for You?
You don’t need to be a programmer to succeed with this book. You’ll be sur-
prised how quickly you become familiar with the Unix command line interface
and the Ruby programming language even if you’ve never tried programming
before.
Book One provides a primer for the Unix command line, the terminal, and a text
editor. If you have no experience with Unix commands, the terminal window,
or a text editor, read Book One first. Everything else you need is self-contained
in this book.
With this book, my aim is to introduce you to Rails and the techniques of web
application development so you can launch a startup or begin a new career.
What To Expect
There is deep satisfaction in building an application and making it run. With
this book, I’ll give you everything you need to build a real-world Rails appli-
cation. More importantly, I’ll explain everything you build, so you understand
how it works. There will be no mystery code.
When you’ve completed this tutorial, you will be ready for more advanced self-
study, including the Capstone Rails Tutorials, textbook introductions to Rails
such as Michael Hartl’s Ruby on Rails Tutorial, or workshops and code camps
that provide intensive training in Ruby on Rails.
opment.
Book One will teach you how to be a successful beginner. There is a roadmap,
or study guide, in the “Level Up” chapter. It helps to have a map because there
is so much to learn. More importantly, to become a skilled Rails developer,
you’ll need to start writing code, and Book One contains a chapter, “Crossing
the Chasm,” that will give you a strategy for building your own applications.
www.dbooks.org
6 CHAPTER 2. INTRODUCTION
After you read this book, you’ll be able to work with the example applications
from the RailsApps Project. The project provides open source example ap-
plications for Rails developers, for free. Each application is accompanied by a
tutorial in the Capstone Rails Tutorials series, so there’s no mystery code. Each
application can be generated in a few minutes with the Rails Composer tool,
which professional developers use to create starter applications.
The open source project is solely supported by subscriptions to the video series
and sales of the Capstone Rails Tutorials. If you get the videos or the advanced
tutorials, you’ll have my sincere appreciation for your support.
Staying In Touch
If you obtained this book from Amazon or a download site, take a moment to
get on the mailing list for the book. I’ll let you know when I release updates to
the book.
This book approaches the subject differently than most introductions to Rails.
In this book, rather than show the student how to use scaffolding, I introduce
the model-view-controller design pattern by creating the components manu-
ally. Lastly, though every other Rails tutorial shows how to use a database, this
book doesn’t, because I want the book to be a short introduction and I believe
the basic principles of a web application stand out more clearly without adding
a database to the application. Though this tutorial is not a typical Rails intro-
duction, I hope you’ll agree that it does a good job in preparing Rails beginners
for continued study, whether it is a course or more advanced books.
WHAT TO EXPECT 7
www.dbooks.org
8 CHAPTER 2. INTRODUCTION
Example Code
If you follow this tutorial closely, you’ll have a working application that closely
matches the example app in the learn-rails GitHub repository. If your applica-
tion doesn’t work after following the tutorial, compare the code to the example
app in the GitHub repository, which is known to work.
Version Check
The code in this tutorial was tested by many people and worked flawlessly at the
time this was written. The learn-rails example application on GitHub serves as
a “reference implementation” if you have problems. The example application
is updated more frequently than the published tutorial.
You’ll find the version number and release date on the first page of this book
www.dbooks.org
10 CHAPTER 3. GET HELP WHEN YOU NEED IT
(under the book title). Check the learn-rails GitHub repository to find out if
you have the newest version of the book. The README page on the GitHub
repo always shows the most recent version number for the book and the tutorial
application.
Don’t worry if the learn-rails GitHub repository seems complicated or difficult
to understand. You’ll get to know GitHub over time and it will become familiar.
For now, it is only important to know that it is there in case you have problems.
Take a moment now to look at the open issues on GitHub to see what problems
you may encounter as you work your way through the tutorial. You can look at
the closed issues to see some of the solved problems.
If you have trouble building the application in this book, and suspect something
may be out of date, you can compare the Gemfile in the repo to see if we’ve
changed gems or specified version numbers to avoid compatibility issues.
You can also check the CHANGELOG and look at recent commits to see the
current state of the application.
• tag your questions on Stack Overflow with railsapps for extra attention
GETTING HELP WITH RAILS 11
If your questions aren’t answered on Stack Overflow, try the Reddit forum:
• /r/rails
I sincerely hope you won’t encounter obstacles as you build the tutorial ap-
plication. Thousands of beginners have successfully completed the book and,
unless a gem has recently changed, you should have no problem.
Now let’s consider where to look for help when you are working on your own
Rails projects.
Video Option
Watch the six minute video if you have subscribed:
www.dbooks.org
12 CHAPTER 3. GET HELP WHEN YOU NEED IT
to similar questions; the most popular answer is not always the correct answer
to your particular problem.
Requests for advice (especially anything that provokes opinions) are often re-
jected on Stack Overflow. Instead, try Reddit for advice or recommendations.
You’ll find discussion forums (“subreddits”) devoted to Rails and Ruby. You
can also visit the Quora question-and-answer site for topics devoted to Rails
and Ruby.
References
Here are suggestions for the most important references.
If you feel overwhelmed by all the links, remember that you can use this book
to build the tutorial application without any additional resources. Right now,
it’s important to know additional help is available when you need it.
RailsGuides
The Rails Guides are Rails’s official documentation, written for intermediate-
level developers who already have experience writing web applications. The
Rails Guides are an excellent reference if you want to check the correct syntax
for Rails code. You’ll be able to use the Rails Guides after completing this
tutorial.
Cheatsheets
Tobias Pfeiffer has created a useful Rails Beginner Cheat Sheet that provides a
good overview of Rails syntax and commands.
Even better than a cheatsheet, for Mac users, is an application named Dash
that offers fingertip access to reference documentation for Ruby, Rails, HTML,
MEETUPS, HACK NIGHTS, AND WORKSHOPS 13
API Documentation
The API documentation for Ruby and Rails shows every class and method.
These are extremely technical documents (the only thing more technical is
reading the source code itself). The documents offer very little help for be-
ginners, as each class and method is considered in isolation, but there are times
when checking the API documentation is the only way to know for certain how
something works.
www.dbooks.org
14 CHAPTER 3. GET HELP WHEN YOU NEED IT
and support. You may find a group that meets weekly for beginners who study
together.
Local user groups often sponsor hack nights or hackathons which can be evening
or weekend collaborative coding sessions. You don’t have to be an expert. Be-
ginners are welcome. You can bring your own project which can be as simple
as completing a tutorial. You will likely find a study partner at your level or a
mentor to help you learn.
If you are a woman learning Rails, look for one of the free workshops from
RailsBridge or Rails Girls. These are not exclusively for women; everyone
considered a “minority” in the tech professions is encouraged to participate;
and men are included when invited by a woman colleague or friend.
Pair Programming
Learning to code is challenging, especially if you do it alone. Make it social
and you’ll learn faster and have more fun.
There’s a popular trend in the workplace for programmers to work side-by-side
on the same code, sharing a keyboard and screen. It’s effective, both to increase
productivity and to share knowledge, and many coders love it. When program-
mers are not in the same office, they share a screen remotely and communicate
with video chat.
Look for opportunities to pair program. It’s the best way to learn to code,
even if your pairing partner is only another beginner. Learn more about pair
programming on the site pairprogramwith.me and find a pairing partner at co-
dermatch.me or letspair.net.
Remote pair programming requires tools for screen sharing and video chat.
Pairing sessions often use:
• Google+ Hangouts
• Screenhero
PAIRING WITH A MENTOR 15
• Floobits
• Cloud9 IDE
Code Review
Code review is an essential part of the development process. There’s always
more than one way to implement a feature, and some ways are better than
others, but you may not know it unless you ask someone to look at your code.
When you pair with a mentor, you get the benefit of code review. But even
www.dbooks.org
16 CHAPTER 3. GET HELP WHEN YOU NEED IT
if you don’t have a mentor, you can get code review online. StackExchange,
the parent of StackOverflow, has a free site for code review, and a new service
promises code review as a service:
• codereview.stackexchange.com
Expert code review will accelerate your learning faster than anything else.
Knowing where to go for help is important; it is just as important to stay cur-
rent.
Staying Up-to-Date
Rails changes frequently and its community is very active. Changes to Rails,
expert blog articles, and new gems can impact your projects, even if you don’t
work full-time as a Rails developer. Consequently, I urge you to stay up-to-date
with news from the community.
I suggest signing up for two weekly email newsletters:
• Ruby Weekly
• Green Ruby News
Another weekly email newsletter is more technical, and focused on code arriv-
ing in the next version of Rails:
For daily news about Rails, check Peter Cooper’s RubyFlow site which lists
new blog posts from Rails developers each day.
Also take a look at this list of top blogs for Rails developers:
STAYING UP-TO-DATE 17
• 45 Ruby Blogs
If you like podcasts, check out Ruby Rogues and Envy Labs’s Ruby5.
Finally, you can follow @rails_apps on Twitter for news about the RailsApps
project.
www.dbooks.org
18 CHAPTER 3. GET HELP WHEN YOU NEED IT
Chapter 4
19
www.dbooks.org
20 CHAPTER 4. ACCOUNTS YOU MAY NEED
GitHub
Rails developers use GitHub for collaboration and remote backup of projects.
For this tutorial, I suggest you get a free personal GitHub account if you don’t
already have one. As a developer, your GitHub account establishes your rep-
utation in the open source community. If you’re seeking a job as a developer,
employers will look at your GitHub account. When you work with other de-
velopers, they may check to see what you’ve worked on recently. Don’t be
reluctant to set up a GitHub account, even if you’re a beginner. It shows you
are serious about learning Rails.
You’ll be asked to provide a username. This can be a nickname or short version
of your real name (for example, your Twitter username).
You’ll be asked to provide an email address. It’s very important that you use
the same email address for your GitHub account that you use to configure Git
locally (there will be more about configuring Git later). If you create a Heroku
account to deploy and host your Rails applications, you should use the same
email address.
After you create your GitHub account, log in and look for the button “Edit Your
Profile.” Take a few minutes to add some public information to your account.
It is really important to provide your real name and a public email address.
Displaying your real name on your GitHub account makes it easy for people
to associate you with your work when they meet you in real life, for example
at a meetup, a hackathon, or a conference. Providing a public email address
makes it possible for other developers to reach you if you ask questions or
submit issues. If you can, provide a website address (even just your Twitter
or Facebook page). In general, you won’t be exposed to stalkers or spammers
(except some recruiters) if you are open about yourself on GitHub.
Later I’ll show you how to set up and use Git and GitHub.
MAILCHIMP 21
MailChimp
This tutorial shows how website visitors can sign up to receive a newsletter
provided by a MailChimp mailing list. MailChimp allows you to send up to
12,000 emails/month to a list of 2000 or fewer subscribers for free. There is no
cost to set up an account.
MailChimp will ask you to provide a website address and company details for
your account. These details are included when email messages are sent to your
subscribers. If you don’t have your own website, you can enter the URL for
your GitHub account for now. Use your own name for a company if you don’t
have one.
After you have set up a MailChimp account, create a new mailing list where
you can collect email addresses of visitors who have asked to subscribe to a
newsletter. The MailChimp “Lists” page has a button for “Create List.” The
list name and other details are up to you.
If you get frustrated with the complex and confusing MailChimp interface, try
to remember that the friendly MailChimp monkey is laughing with you, not at
you.
SendGrid
Earlier editions of this book showed how to use a Gmail account to send email
from the application. Google has taken steps to make Gmail more secure and
now it can be difficult to send email from a Rails application using Gmail.
This tutorial provides instructions for SendGrid. SendGrid offers a free account
that allows you to send 12,000 messages per month for free.
Scroll to the bottom of the SendGrid pricing page to see details about the free
plan. Click the “Try for Free” link to set up an account. No credit card is
needed.
www.dbooks.org
22 CHAPTER 4. ACCOUNTS YOU MAY NEED
Heroku
We’ll use Heroku to host the tutorial application so anyone can reach it.
To deploy an app to Heroku, you must have a Heroku account. Visit https://signup.heroku.co
to set up an account.
Be sure to use the same email address you used to register for GitHub. It’s
very important that you use the same email address for GitHub and Heroku
accounts.
Chapter 5
Get Started
Before you can start building, you’ll need to install Ruby (the language) and
Rails (the gem). I’ll provide links to installation instructions that are up to
date. Even if you’ve already installed Rails, please review the instructions to
make sure your development environment is set up correctly. Other books and
tutorials often skip important details.
I’ve explained how to use a text editor and terminal application in Book One.
If you haven’t used the Unix command line before, refer to Book One for an
introduction.
I recommend the Atom text editor but you may use Sublime Text or any others
that provide syntax highlighting. Refer to Book One for important instructions
about setting up the text editor so you can open a file from the command line.
23
www.dbooks.org
24 CHAPTER 5. GET STARTED
This book is available in several formats, including online (HTML), PDF, ePub
(Apple iBooks), and mobi (Kindle) versions.
Use the online edition of the book if you can. With the online edition, you’ll be
able to copy and paste the code without any problem. The ePub version (using
Apple iBooks) also preserves line breaks and indentation when copying code.
Copying without line breaks will cause code errors. You’ll lose line breaks when
copying code with the following versions:
YOUR COMPUTER 25
• mobi (Kindle)
If you use Adobe Acrobat you’ll be able to copy the line breaks (though indenting
is lost). You can also open a PDF file in Chrome or Safari web browsers and copy
code with line breaks. With the mobi (Kindle) version, you’ll have to carefully
reformat the code after pasting into your text editor.
Indentation makes code more readable, so try to preserve the indentation you see
in the code samples. In YAML files (with the file extension .yml), indentation is
required (your application will break without it).
Your Computer
You can develop web applications with Rails on computers running Mac OS
X, Linux, or Microsoft Windows operating systems. Most Rails developers use
macOS or Linux because the underlying Unix operating system has long been
the basis for open source programming.
Later in this chapter, I’ll give links to installation instructions for macOS and
Linux.
For Windows users, I have to say, installing Rails on Windows is frustrating
and painful. Readers and workshop students often tell me that they’ve given
up on learning Rails because installation of Ruby on Windows is difficult and
introduces bugs or creates configuration issues. Even when you succeed in
getting Rails to run on Windows, you will encounter gems you cannot install.
For these reasons, I urge you to use Cloud9, a browser-based development
environment, on your Windows laptop.
www.dbooks.org
26 CHAPTER 5. GET STARTED
Hosted Computing
If you are using Windows, or have difficulty installing Ruby on your computer,
try using Cloud9.
Cloud9 provides a hosted development environment. That means you set up
an account and then access a remote computer from your web browser. The
Cloud9 service is free for ordinary use. There is no credit card required to set
up an account. You’ll only be charged if you add extra computer memory or
disk space (which you don’t need for ordinary Rails development).
The Cloud9 service gives you everything you need for Rails development, in-
cluding a Unix shell with Ruby pre-installed, plus a browser-based file man-
ager and text editor. Any device that runs a web browser will give you access
to Cloud9, including a tablet or smartphone, though you need a broadband con-
nection, a sizable screen, and a keyboard to be productive.
On the Mac, search for the macOS Terminal application by pressing the Command-
Spacebar combination (which Apple calls “Spotlight Search”) and searching
for “Terminal.” The magnifying glass in the upper right corner of your screen
will also launch “Spotlight Search.” Or look in the Applications/Utilities/
folder for the Terminal application. You’ll need to click the name of the ap-
plication to launch the Terminal.
INSTALLING RUBY 27
For Linux or Windows, The Command Line Crash Course explains how to
launch a terminal application.
Launch your terminal application now.
Try out the terminal application by entering a shell command.
$ whoami
Don’t type the $ character. The $ character is a cue that you should enter a
shell command. This is a longtime convention that indicates you should enter
a command in the terminal application or console.
The Unix shell command whoami returns your username.
Don’t type the $ prompt.
You might see:
Installing Ruby
Your first challenge in learning Rails is installing Ruby on your computer.
www.dbooks.org
28 CHAPTER 5. GET STARTED
Frankly, this can be the most difficult step in learning Rails because no tutorial
can sort out the specific configuration of your computer. Get over this hump
and everything else becomes easy.
The focus of this book is learning Rails, not installing Ruby, so to keep the
book short and readable, I’m going to give you links to articles that will help
you install Ruby.
You’ll spend at least an hour installing Ruby and Rails, so be sure to allow
enough time for the task.
MacOS
See this article for macOS installation instructions:
Install Ruby on Rails - MacOS
Ubuntu Linux
See this article for Ubuntu installation instructions:
Install Ruby on Rails - Ubuntu
Hosted Computing
Cloud9 is a browser-based development environment. Cloud9 is free for small
projects. If you have a fast broadband connection to the Internet, this is your
best choice for developing Rails on Windows. And it is a good option if you
have any trouble installing Ruby on Mac or Linux because the Cloud9 hosted
environment provides everything you need, including a Unix shell with Ruby
and RVM pre-installed, plus a browser-based file manager and text editor. Us-
ing a hosted development environment is unconventional but leading develop-
ers do so and it may be the wave of the future.
YOUR WORKSPACE 29
Windows
Cloud9 is ideal if you have a fast Internet connection. If not, download the
Railsbridge Virtual Machine to create a virtual Linux computer using Vagrant.
Other tutorials may suggest using RailsInstaller, but it will not provide an up-
to-date version of Ruby or Rails. Also, RVM does not run on Windows.
Your Workspace
Take a moment to think about where on your computer you’ll do your work
and store your files. You may have a documents/ folder. You could make a
similar folder named projects/ or code/ or workspace/ for your programming
projects. Use the Unix mkdir command to create a folder or create it with your
file browser.
www.dbooks.org
30 CHAPTER 5. GET STARTED
$ cd ~
$ pwd
/Users/danielkehoe
$ mkdir workspace
$ cd workspace
In this tutorial, the terms “folders” and “directories” mean the same thing.
Use the Unix cd command to change directories.
When you enter the Unix command cd ~, you’ll move to your home (or
“user”) directory. The squiggly ~ “tilde” character is a Unix shortcut that indi-
cates your home folder.
The Unix pwd command shows the “present working directory,” where you are.
The Unix mkdir command creates an empty folder and we move into it with
the Unix cd command.
Video Option
Watch the four minute video if you have subscribed:
A major release includes new features, including changes which break back-
ward compatibility. For example, switching from Rails 3.2 to Rails 4.0 required
a significant rewrite of every Rails application.
A minor release introduces new features but doesn’t break anything. For ex-
ample, Rails 3.2 added the asset pipeline, and Rails 4.2 added the Active Job
feature for background processing.
A patch release fixes bugs but doesn’t introduce significant features. Usually
this means you can change the version number in the Gemfile and run bundle
update without making any other changes to your application.
$ ruby -v
www.dbooks.org
32 CHAPTER 5. GET STARTED
You’ve got Ruby version 2.4.1, patch level “p0” (Ruby versions add an extra
patch level to semantic versioning). If you’ve got a newer version of Ruby, no
problem; minor updates to Ruby don’t affect Rails.
Try:
$ rails -v
Rails 5.1.2
If you see:
You are not using an RVM gemset where the Rails gem is installed. Go to the
Installing Rails instructions for your computer if you have not set up Rails. The
next section explains more about RVM gemsets which may be all you need to
find Rails.
If you have Rails 4.2 or older versions, you must update to Rails 5.1. See the
Installing Rails instructions for your computer.
Versions such as 5.0.0.beta3 or 5.0.0.rc1 are beta versions or “release
candidates.” You can use a release candidate in the weeks before a final release
becomes available.
If you’ve got Rails 5.1.3 or newer, that’s fine. It means minor bugs have been
fixed since this was written, but the book is still current. You can check for the
current version of Rails here.
RVM 33
This edition of the book was prepared using Rails 5.1.2. The newest version of the
book is listed on the README page of the learn-rails GitHub repository.
RVM
I promised that this book would introduce you to the practices of professional
Rails developers. One of the most important utilities you’ll need in setting up
a real-world Rails development environment is RVM, the Ruby Version Man-
ager.
RVM lets you switch between different versions of Ruby. Right now, that might
not seem important, but as soon as a new version of Ruby is released, you’ll
need to upgrade, and it is best to be ready by installing the current version of
Ruby with RVM, so you can easily add a new version of Ruby later, and still
switch back to older versions as needed.
RVM also helps you manage your collections of gems, by letting you create
multiple gemsets. Each gemset is the collection of gems you need for a specific
project. Rails changes frequently; with RVM, you can install a specific version
of Rails in a project gemset, along with all the gems you need for the project.
When a new version of Rails is released, you can create a new gemset with the
new Rails version when you start a new project. Your old project will still have
the version of Rails it needs in its own gemset.
If you’ve followed the instructions in the article Installing Rails and installed
RVM, you’ll be ready to handle multiple versions of Ruby, and multiple ver-
sions of Rails. That’s as it should be. Most professional Rails developers have
more than one version of Ruby or Rails, and RVM makes it easy to switch.
www.dbooks.org
34 CHAPTER 5. GET STARTED
$ rvm list
You can see a list of available gemsets associated with the current Ruby version:
After you’ve worked on a few Rails applications, you’ll see several project-
specific gemsets if you are using RVM in the way most developers do.
RVM is not the only utility you can use to manage multiple Ruby versions.
Some developers like Chruby or rbenv. Don’t be worried if you hear debates
about RVM versus Chruby or rbenv; developers love to compare the merits of
their tools. RVM is popular, well-supported, and an excellent utility to help a
developer install Ruby and manage gemsets; that’s why we use it.
PROJECT-SPECIFIC GEMSET 35
Project-Specific Gemset
For our learn-rails application, we’ll create a project-specific gemset using
RVM. We’ll give the gemset the same name as our application.
By creating a gemset for our tutorial application, we’ll isolate the current ver-
sion of Rails and the gems we need for this project. Whether you use RVM
or another Ruby version manager, this will introduce you to the idea of “sand-
boxing” (isolating) your development environment so you can avoid conflicts
among projects.
After we create the project-specific gemset, we’ll install the Rails gem into the
gemset. Enter these commands:
This will install the newest version of Rails 5.0. It takes a few minutes to
automatically install all the gems that are needed for Rails.
It’s absolutely necessary to create a gemset and install Rails so we can move on
to creating the application in the next chapter. If you have trouble at this point,
refer to the article Installing Rails or the RVM website. Linux users may need
to check instructions for Integrating RVM.
Let’s make sure Rails is ready to run. Open a terminal and type:
$ rails -v
You should see the message “Rails 5.1.2” (or something similar).
Now let’s explore the rails new command and get started building the tuto-
rial application.
www.dbooks.org
36 CHAPTER 5. GET STARTED
Chapter 6
Starter Applications
Rails provides a framework; that is, a software library that provides utilities,
conventions, and organizing principles to allow us to build complex web ap-
plications. Without a framework, we’d have to code everything from scratch.
Rails gives us the basics we need for many websites.
Still, the framework doesn’t give us all the features we need for many common
types of websites. For example, we might want users to register for an account
and log in to access the website (“user management and authentication”). We
might want to restrict portions of our website to just administrators (“authoriza-
tion”). We also might want to add gems that enhance Rails to aid development
(gems for testing, for example) or improve the look and feel of our application
(the Bootstrap or Foundation front-end frameworks). Developers often mix and
match components to make a customized Rails stack.
Developers often use a starter application instead of assembling an application
37
www.dbooks.org
38 CHAPTER 6. CREATE THE APPLICATION
from scratch. You might call this a “template” but we use that term to refer to
the view files that combine HTML with Ruby code to generate web pages. Most
experienced developers have one or more starter applications that save time
when beginning a new project. The RailsApps project was launched to provide
open source starter applications so developers could collaborate on their starter
applications and avoid duplicated effort. After you gain some skill with this
tutorial, you might use the RailsApps starter apps to instantly generate a Rails
application with features like authentication, authorization, and an attractive
design. At the end of this book, you’ll learn about Rails Composer, a tool for
building starter applications.
For now, we’ll begin with the Rails default starter application.
$ pwd
/Users/danielkehoe/workspace/
If you’re not in your workspace folder, enter a Unix command to move to the
folder:
$ cd ~/workspace
We already created a project-specific gemset using RVM. Make sure it’s ready
to use:
You should see an arrow pointing to the learn-rails gemset. If not, go back
to the previous “Get Started” chapter.
$ cd learn-rails
This is your project directory. It is also called the application root directory.
You’ll spend all your time inside this folder.
www.dbooks.org
40 CHAPTER 6. CREATE THE APPLICATION
After creating a new Rails application, you may see a message to run a command:
Type the ls command to show the folders and files in a directory. Soon we’ll
learn more about each of these folders and files.
$ ls
Gemfile Rakefile config lib test
Gemfile.lock app config.ru log tmp
README.md bin db public vendor
$ ls -1pa
./
../
.gitignore
.ruby-gemset
.ruby-version
Gemfile
Gemfile.lock
README.md
Rakefile
app/
bin/
config/
config.ru
db/
lib/
log/
public/
test/
tmp/
vendor/
The “a” flag in the Unix ls -1pa command displays hidden files. Each hidden
file is listed with a dot (period or full stop) at the beginning of the filename.
You’ll notice .ruby-gemset and .ruby-version.
You’ll also see two “special files” which are not files at all:
www.dbooks.org
42 CHAPTER 6. CREATE THE APPLICATION
If you’re using Cloud9, you must change preferences to see hidden files. In the
window that contains the file list, there is a gear icon (dark in color and difficult to
see). Clicking the gear option will give you options:
You must select all three options to see the hidden files.
MAKE A STICKY GEMSET 43
That’s a brief diversion into Unix; let’s try running our new Rails application.
www.dbooks.org
44 CHAPTER 6. CREATE THE APPLICATION
$ rails server
Alternatively, to save typing, you can abbreviate the rails server com-
mand:
$ rails s
If you are using the Cloud9 hosted service, you’ll need to enter bin/rails
server -p $PORT -b $IP.
You’ll see:
The rails server command launches the Puma web server that is provided
with Rails.
TEST THE APPLICATION 45
You need to install Node.js. For help, see Install Ruby on Rails - Ubuntu.
It is easy to see your web application in action on your local computer. If you are
using a hosted service such as Cloud9, it is a little more complicated.
If you are using Cloud9, click the “Preview” link in the IDE menu (at the top of
the page). There is a “Run” link, too, but it doesn’t work if you have created your
Rails application in a folder within the workspace/ folder. You can also open a
browser tab or window and enter the URL for the application, as hosted by Cloud9.
When you launch the Rails server, Cloud9 displays a helpful message showing the
URL where you can view your application.
www.dbooks.org
46 CHAPTER 6. CREATE THE APPLICATION
Open the file log/development.log and you’ll see the same messages. When a
browser sends requests to the Puma web server, diagnostic messages are written
to the console and to the log/development.log file. These diagnostic messages
are an important tool for troubleshooting when you are developing.
You can keep more than one terminal window open. For convenience, you may
want to keep a terminal window open for running the web server and watch-
ing diagnostic messages. In the Terminal or iTerm2 applications, Command-t
opens additional console sessions in new “tabs.”
Developers typically open more than one terminal window when they work on
a Rails application. They’ll start the server with the rails server command
in one window (or tab) and watch the log messages. In another window (or
tab), they’ll enter commands as they build the application. They might create
folders with a Unix command, run generators, or try out code with the rails
console command (you’ll learn about the rails console command in the
“Troubleshoot” chapter).
To some people, the text editor and the terminal window look very similar.
When you work on a file in a text editor, you make changes to one file, in
one place. The terminal window is very different. Your computer can run
multiple programs at once. You can open multiple terminal windows. In each
terminal window, you can use the command line to launch a different program.
Each program you start in a terminal window is a separate process and multiple
processes can run simultaneously. You can end a process by pressing Control-
c (in most cases), Control-d (in some cases), or closing the terminal window
(almost always). From this perspective, a terminal window is a tool you use to
launch processes and your computer is a machine that runs processes.
GET ORGANIZED FOR EFFICIENCY 47
www.dbooks.org
48 CHAPTER 6. CREATE THE APPLICATION
vertical height. If you are using Atom or Sublime Text, you can open two editor
panels side-by-side. Some developers find it helpful to leave the file browser
panel open to navigate the project directory; others hide the file browser panel
to save space.
If you have enough screen space, leave your web browser open and place it next
to your text editor. If your screen space is limited, you may have to overlap the
web browser with the text editor, but position your web browser window so
you can bring it to the front with a single click. You’ll need multiple tabs
open in your web browser. Unless you like constant distraction, close Gmail,
Facebook, Twitter, and Hacker News. Open tabs for http://localhost:3000/, this
tutorial, and additional references or documentation.
On the Mac, there are window management utilities that reposition windows
with just a click or keyboard command; I use Moom but you can find others if
you search for “mac window management utilities.”
This is just a guide; I’m sure you can improve upon these suggestions.
Chapter 7
49
www.dbooks.org
50 CHAPTER 7. THE PARKING STRUCTURE
Video Option
Watch the eleven minute video if you have subscribed:
Project Directory
Use the Unix ls command to list the contents of the project directory. For a
one-column list that shows each subdirectory (marked with a slash), we’ll add
the -1p option to the command.
$ ls -1p
You’ll see:
Gemfile
Gemfile.lock
README.md
Rakefile
app/
bin/
config/
config.ru
db/
lib/
log/
public/
tmp/
vendor/
Now is a good time to open a file browser window and look at the contents of
the project directory. On the Mac, there’s a command you can use to open the
graphical file browser from the console. If you’re in the project directory, type
open .. The period (or “dot”) is a Unix symbol that means “the directory I’m
in.”
GET TO KNOW THE FOLDERS AND FILES 51
$ open .
You’ll learn more about each file and folder as you proceed through the tutorial.
To get you started, here are three tables. The first describes the files and folders
that are important for every beginner. The second table describes the files and
folders that you can ignore. The third table is a preview of things to come.
www.dbooks.org
52 CHAPTER 7. THE PARKING STRUCTURE
The test/ folder is present in the default Rails starter app. You’ll use the test/
folder when you learn about test-driven development. Many Rails developers
THE APP DIRECTORY 53
use a different gem for testing, named RSpec, and your RSpec tests will go in
a spec/ folder.
You can also use your text editor to view the folder.
Or do it with Unix commands:
$ cd app
$ ls -1p
assets/
channels/
controllers/
www.dbooks.org
54 CHAPTER 7. THE PARKING STRUCTURE
helpers/
jobs/
mailers/
models/
views/
Whether you use the file browser, Unix commands, or your text editor, you are
looking at the same file system.
Most of the work of developing a Rails application happens in the app/ folder.
Earlier we described Rails as “a set of files organized with a specific structure.”
We said the structure is the same for every Rails application. The app/ directory
is a good example. The folders in the app/ directory are the same in every
Rails application. This makes it easy to collaborate with other Rails developers,
providing consistency and predictability.
• assets
• channels
• controllers
• helpers
• jobs
• mailers
• models
• views
You may recall our earlier description of Rails from the perspective of a soft-
ware architect. In this folder, you’ll see evidence of the model–view–controller
design pattern. Three folders named models/, views/, and controllers/ enforce
the software architect’s “separation of concerns” and impart structure to our
THE APP DIRECTORY 55
code. As you build the application, we’ll explain the role of the MVC compo-
nents in greater detail.
Five folders play supporting roles. The mailers folder is for code that sends
email messages. The helpers folder is for Rails view helpers, snippets of
reusable code that generate HTML. Later, when we learn more about views,
we’ll say view helpers are like “macros” that expand a short command into a
longer string of HTML tags and content. Rails 3.1 added the assets/ folder as a
location for CSS and JavaScript files. The jobs/ folder is for background jobs
built with the Rails ActiveJob feature. Rails 5.0 added the channels/ folder for
the ActionCable feature which uses WebSockets for real-time communication
between web server and browser.
If you join a project to work on a large and complex Rails application, you
may see folders such as these in the app/ directory. As an application grows in
complexity, an experienced software architect may suggest reducing the size of
models and controllers by moving code to “POROs” (plain old Ruby objects).
Code in any folder in the app/ directory is shared throughout a Rails appli-
cation without any additional configuration (in contrast, code you add to the
lib/ directory is only available with some extra work). Rails provides a basic
model–view–controller framework but it is often necessary to extend it with
code in a services/ folder. Similarly, a policies/ folder can be used to consoli-
date code that controls access to various features or pages of a web application.
Use the cd .. command (“change directory dot dot”) to return to the project
directory.
www.dbooks.org
56 CHAPTER 7. THE PARKING STRUCTURE
$ cd ..
$ pwd
/Users/danielkehoe/workspace/learn-rails
As a Rails developer, you’ll spend most of your time navigating the hierarchy
of folders as you create and edit files. And because Rails provides a consistent
structure, you’ll quickly find your way on any unfamiliar project.
Chapter 8
57
www.dbooks.org
58 CHAPTER 8. TIME TRAVEL WITH GIT
we may be saving typos or unfinished code that doesn’t work. Every so often,
we get to a point where a task is finished; we’ve fixed all our errors and our
code runs. We want to preserve the state of our work. That’s when we need a
version control system.
A version control system does more than a software application’s “Save” com-
mand. Like a “Save” command, it preserves the current state of our files. It
also allows us to add a short note that describes the work we’ve done. More
importantly, it archives a snapshot of the current state in a repository where it
can be retrieved if needed.
Here’s where the time travel comes in. We can go back and recover the state
of our work at any point where we committed a snapshot to the repository. In
software development, travel to the past is essential because we often make
mistakes or false starts and have to return to a point where we know things
were working correctly.
What about time travel to the future? Often we need to try out code we may
decide to discard, without disturbing work we’ve done earlier. Version control
systems allow us to explore alternative futures by creating a branch for our
work. If we like what we’ve done in our branch, we can merge it into the main
trunk of our software project.
Unlike time travel in the movies, we can’t travel back to any arbitrary point in
the flow of time. We can only travel to past or future states we’ve marked as
significant by checking our work into the repository.
Git
The dominant version control system among Rails developers is Git, created
by the developer of the Linux operating system.
Unlike earlier version control systems, Git is ideal for wide-scale distributed
open source software development. Combined with GitHub, the “social cod-
ing” website, Git makes it easy to share and merge code. When you work with
GIT 59
others on a project, your Git commit messages (the notes that accompany your
snapshot) offer a narrative about the progress of the project. Well-written com-
mit messages describe your work to co-workers or open source collaborators.
GitHub’s support for forking (making your own copy of a repository) makes
it possible to take someone else’s project and modify it without impacting the
original. That means you can customize an open source project for your own
needs. You can also fix bugs or add a feature to an open source project and
submit a pull request for the project maintainer to add your work to the original.
Fixing bugs (large or small) and adding features to open source projects are how
you build your reputation in the Rails community. Your GitHub account, which
shows all your commits, both to public projects and your own projects, is more
important than your resumé when a potential employer considers hiring you
because it shows the real work you have done.
Collaboration is easy when you use a branch in Git. If you and a coworker
are working on the same codebase, you can each make a branch before adding
to the code or making changes. Git supports several kinds of merges, so you
can integrate your branch with the trunk when your task is complete. If your
changes collide with your coworker’s changes, Git identifies the conflict so you
can resolve the collision before completing the merge.
All the power of Git comes at a price. Git is difficult for a beginner to learn,
largely because many of its procedures have no real-world analog. Have you
noticed how time travel movies require mental gymnastics, especially when
you try to make sense of alternative futures and intersecting timelines? Git is a
lot like that, mostly because we use it to do things we don’t ordinarily do in the
real world.
In this tutorial, you won’t encounter Git’s advanced procedures, like resolving
merges or reverting to earlier versions. We’ll stick to the basics of archiving
our work (and in one case, discarding work that we’ve done for practice). You
can build the tutorial project without using Git. But I urge you to use Git and
a GitHub account for this project, for two reasons. First, with your tutorial
application on GitHub, you’ll show potential employers or collaborators that
you’ve successfully built a useful, functioning Rails application. More impor-
www.dbooks.org
60 CHAPTER 8. TIME TRAVEL WITH GIT
tantly, you must get to know Git if you plan to do any serious coding, either as
a professional or a hobbyist.
Before I show you Git commands, I want to mention that some people use
graphical client applications to manage Git. MacOS has GitHub for Mac, Git
Tower, and other Mac Git clients. Graphical applications for Git are useful for
colleagues who don’t use a Terminal application, such as graphic designers or
writers. There’s no need for you to install these applications. Every developer
I’ve met uses Git from the command line. It will take effort to master Git; the
commands are not intuitive. But it is absolutely necessary to become familiar
with Git basics.
Before you do any work on the tutorial application, I’ll show you the basics of
setting up and using Git.
Is Git Installed?
As a first step, make sure Git is installed on your computer:
$ which git
/usr/local/bin/git
$ git version
git version ...
If Git is not found, install Git. See the article Rails with Git and GitHub for
installation instructions.
Is Git Configured?
Make sure Git knows who you are. Every time you update your Git repository
with the git commit command, Git will identify you as the author of the
changes.
CREATE A REPOSITORY 61
You should see your name and email address. If not, configure Git:
Use your real name so people will associate you with your work when they
meet you in real life. There’s no reason to use a clever name unless you have
something to hide. And use your full name, not just your first name.
Use the same email address for Git, your GitHub account, and Heroku to avoid
headaches.
Create a Repository
Now we’ll add a Git repository to our project. It’s a basic step you’ll repeat
every time you create a new Rails project.
Extending the time traveler analogy, initializing a Git repository is equivalent
to setting up the time machine.
Be sure you are in your project directory, not your user home directory or some-
where else. Use the pwd command to check:
$ pwd
/Users/danielkehoe/workspace/learn-rails
The git init command sets up a Git repository (a “repo”) in the project
directory. We add the Unix symbol that indicates Git should be initialized in
the current directory (git init dot):
www.dbooks.org
62 CHAPTER 8. TIME TRAVEL WITH GIT
$ git init .
Initialized empty Git repository in ...
It creates a hidden folder named .git/ in the project directory. You can peek at
the contents:
$ ls -1p .git
HEAD
config
description
hooks/
info/
objects/
refs/
All Git commands operate on the hidden files. The hidden files record the
changing state of your project files each time you run the git commit com-
mand. There is no reason to ever edit files inside the hidden .git/ folder (doing
so could break your time machine).
GitIgnore
The hidden .git/ folder contains the Git repository with all the snapshots of
your changing project. The snapshots are highly compressed, only containing
records of changes, so the repository takes up very little file space relative to
the project as a whole.
Not every file should be included in a Git snapshot. Here are some types of
files that should be ignored:
• database files
GITIGNORE 63
Git gives us an easy way to ignore files. A hidden file in the project directory
named .gitignore can specify a list of files that are never seen by Git. The
rails new command creates a .gitignore file with defaults that include log
files and database files. Later, when we add configuration files that include
secrets, we’ll update the .gitignore file.
Take a look at the contents of the .gitignore file. We use the Unix cat com-
mand to display the contents of the file:
$ cat .gitignore
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'
For a .gitignore file that ignores more, see an example .gitignore file from the
RailsApps project.
www.dbooks.org
64 CHAPTER 8. TIME TRAVEL WITH GIT
Git Workflow
Your workflow with Git will move through four distinct phases as you add or
edit files.
Untracked Files
The first phase is a “dirty” state of untracked and changed files, before any
snapshot. The git status command lists all folders or files that are not
checked into the repository.
$ git status
On branch master
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
Gemfile
Gemfile.lock
README.md
Rakefile
app/
bin/
config.ru
config/
db/
lib/
log/
public/
test/
tmp/
vendor/
nothing added to commit but untracked files present (use "git add" to track)
In the online version of this book (the HTML version), the example above
appears in green. In the terminal window on your computer, it will be red,
showing you untracked files.
GIT WORKFLOW 65
Here the git status command tells us that we have many untracked files.
We have created new files and they are saved on the computer’s hard disk but
nothing has been recorded in the Git repository.
Staging
I call this step, “Pose for your snapshot.”
Recording files in the Git repository takes two steps: staging and committing.
There will be times when you change many files at once. For example, you
may fix a bug, add a new graphic, and change a form. You might think you’d
like to have Git automatically record all the changes as you save each file. But
the story of your project would be confusing and overly detailed. Git requires
you to mark one or more files (“staging”) before recording the changes (“com-
mitting”). This gives you fine-grained control over the recorded history of your
project.
You can mark individual files to be staged:
Adding individual files allows you to selectively record the history of your
project. For example, you might stage and commit a series of bug fixes before
you stage and commit new features. Applying the time traveler analogy, it will
be easier to travel back to look at bug fixes if they are not mixed in with new
features.
More often, you’ll mark all the files to be staged. Do so now:
$ git add -A
Running git status will show you a long list of files that are staged and
ready to commit.
www.dbooks.org
66 CHAPTER 8. TIME TRAVEL WITH GIT
• git add . adds all new files and changed files, except deleted files
If it seems nonsensical that the command git add -A “adds deletions,” don’t
worry. Like time travel, Git will stretch your understanding of what makes
sense.
Most often, you can simply use the git add -A form of the command.
Now that you’ve marked the files that will be committed to the repository,
you’ve told everyone to pose, and you’re ready to take the snapshot.
Committing
The previous step, the “posing” step, or staging, gives you an opportunity to
select particular files before you commit. If you’ve only worked on one feature,
you’ll likely stage and commit all your files.
The next step is a “commit” which I like to call, “clicking the snapshot.”
When you “make a commit”, you include a message that describes the work
you’ve done. For a time traveler, the “commit message” is important; you
are leaving a trail to help you find your way into the past. Google will show
you dozens of blog posts about “writing better commit messages” but common
sense can be your guide. For example, writing “fix registration form to catch
blank email addresses” will be more helpful than merely writing “fix bugs.”
And if you wonder why commit messages are commonly written in the imper-
ative not past tense (“fix” not “fixed”), it’s a time traveler convention.
Now commit your project to the repository:
GIT WORKFLOW 67
$ git status
On branch master
nothing to commit, working directory clean
You’ve recorded your snapshot locally. Next let’s see a list of previous snap-
shots. Then we’ll learn how to save your snapshots remotely to GitHub.
Git Log
You can use the git log command to see your project history:
$ git log
commit 8da41eec9e864ed91b4a445d8cefdf7893e2faf6
Author: Daniel Kehoe <[email protected]>
Date: Fri Dec 18 10:30:12 2015 +0700
Initial commit
The long string of characters that follows “commit” is an ID, or marker, that
will help you travel back in time if you need to do so.
If you get “stuck” in git log, type q to return to the command prompt.
I like to use the git log command with an option for a compact listing:
www.dbooks.org
68 CHAPTER 8. TIME TRAVEL WITH GIT
Don’t worry if your console doesn’t show 8da41ee. The ID for your commit
will be different.
The listing is easier to review when it is displayed in a compact format. The
commit ID is abbreviated but it is all you need to travel back in time.
Repositories
When we talk about repositories, or “repos,” we mean the archive of our git
commits. The local repo is located in the hidden folder named .git/ in the
project directory. Of course, if your hard drive crashes, or your computer is
lost or stolen, you’ll lose your local repo along with your project. So it is wise
to save your repository in the cloud. The GitHub site is a place to save repos-
itories. GitHub is also a place for collaboration. Most Rails developers save
their repositories to Github, as either a public repo for open source projects, or
a private repo for proprietary projects.
Pushing to GitHub
We’ve seen three phases of the Git workflow: untracked, staged, and commit-
ted.
A fourth stage is important when you work with others: pushing to GitHub.
The repositories hosted on your GitHub account establish your reputation as a
Rails developer for employers and developers you may work with. Even if your
first project is copied from a tutorial, it shows you are serious about learning
Rails and studying conscientiously.
Did you create a GitHub account? Now would be a good time to add your repo
to GitHub.
GIT WORKFLOW 69
Go to GitHub and create a new empty repository for your project. Name the
repository “learn-rails” and give it a description. If the repository is public,
hosting on GitHub is free. Don’t be reluctant to go public with an unfinished
or half-baked project; everyone expects projects on GitHub to be works in
progress.
Add GitHub as a remote repository for your project and push your local project
to GitHub. Before you copy and paste the command, notice that you need to in-
sert your own GitHub account name. In other words, change YOUR_GITHUB_ACCOUNT
in the command shown below.
The -u option sets up Git so you can use git push in the future without
explicitly specifying GitHub as the destination.
Now you can view your project repository on GitHub at:
• https://github.com/YOUR_GITHUB_ACCOUNT/learn-rails
www.dbooks.org
70 CHAPTER 8. TIME TRAVEL WITH GIT
You may notice that the README.md file is automatically incorporated into
the home page of the project repository on GitHub. For our next step, we’ll
update the README file, commit it to the local repo, and push it up to GitHub.
It will be good practice for using Git.
The README
Changing the README file is a good way to practice with Git. It’s also a good
habit to edit the README file whenever you create a new project. It’s easy to
neglect the README for little projects that you’ve just started. But replacing
a default README file shows you are a disciplined, conscientious developer
who will be a good collaborator.
The new README file can be brief. Just state your intentions and acknowl-
edge any code you’ve borrowed. For this project you could say, “Excited to
learn Rails with help from Daniel Kehoe’s book!”
In your text editor, open the file README.md and replace the contents:
# Learning Rails
GitHub lets you add formatting using your choice of markup syntax, depending
on the file extension you add to the filename:
We’ll use Markdown syntax by adding the # character before the first line of
text to force a headline. And we’ll add a link that leads to the learn-rails.com
website.
THE README 71
There’s no requirement that you use Markdown syntax in your README file.
Markdown simply is a popular way to add formatting to improve readability.
Use git status to see what has changed:
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
Here’s our typical workflow. We’ll stage and commit the change:
$ git add -A
$ git commit -m "update README"
If you decide not to use GitHub for this tutorial, you can skip this step (and
skip it throughout the tutorial).
Take a look at your GitHub repository (refresh the web page). Very cool! The
README file has been updated.
The git log command will display your project history:
www.dbooks.org
72 CHAPTER 8. TIME TRAVEL WITH GIT
To learn more about Git, I recommend the book Learn Enough Git to Be Dan-
gerous by my colleague Michael Hartl. An online version is available for free.
Now that you’re comfortable with Git, we can begin customizing our new Rails
application.
Chapter 9
Gems
The art of selecting gems is at the heart of Rails development. I explained
earlier that gems are packages of code, “software libraries,” that have been
developed and tested by other developers. Some gems add functionality or
features to a website. Other gems play a supporting role, making development
easier or implementing basic infrastructure. Gems are open source. They are
available at no charge and can be freely copied and modified.
Videos
• Find Rubygems
73
www.dbooks.org
74 CHAPTER 9. GEMS
RubyGems
It is a mark of honor to release a gem for public use, and a developer’s reputa-
tion can be established when a gem becomes popular and widely used. Gems
are often created when a developer has used the same code as a component in
more than one web application. He or she will take time to release the code as
a gem. That’s how the Rails ecosystem was built, gem by gem since 2004.
There is no evaluation or review process in publishing gems. Gems are hosted
on a public server, rubygems.org. Gems are mostly text files (like any other
Ruby code), organized in a particular format with some descriptive information
(in a gemspec file), and compressed and archived as a single file. A single
command, gem push, uploads a gem to the rubygems.org server for anyone to
use.
Over 50,000 gems have been released since rubygems.org was established.
Some of these gems are used by one or two developers on their own projects.
Many others have been neglected and abandoned due to lack of interest. Only
a few thousand gems are popular and widely used. As a Rails developer, you
must master the art of finding and evaluating gems so you can base your appli-
cations on the tried-and-true work of others.
There is no single authoritative source of recommendations for gems. The
Ruby Toolbox website categorizes and ranks many gems by popularity, and it
is a good place to begin hunting for useful gems. Other than that, it is useful
to study example applications and search for blog posts to find which gems
are most often recommended. When you find an interesting gem, search Stack
Overflow or Google to see what people are saying. Look at the gem’s GitHub
repository and check:
Popular gems are likely to have many reported issues, some of which are trivial
problems or feature requests. Gems that are actively maintained will have many
closed issues and, ideally, only a few open issues. When you find a gem that
has many open issues and no recently closed issues, you’ve probably found a
gem that has been abandoned. Also look at the commit log, which you’ll find
on the GitHub project page in a tab at the top of the page. Regular and recent
activity in the commit log indicates the gem is actively maintained.
Rails Gems
Rails itself is a gem that, in turn, requires a collection of other gems. This
becomes clear if you look at the summary page for Rails on the rubygems.org
site. On that page, you’ll see photos of the Rails core team. More importantly,
you’ll see a list of gems that are required to use Rails:
www.dbooks.org
76 CHAPTER 9. GEMS
These are the “runtime dependencies” for Rails. Each of these gems has its
own dependencies as well. When you install Rails, a total of 63 gems are
automatically installed in your development environment.
You may not need a SQLite database, SCSS for stylesheets, or the others, but
many developers use these tools so they are included in the default starter ap-
plication.
WHERE DO GEMS LIVE? 77
$ gem env
RubyGems Environment:
- RUBYGEMS VERSION: 2.6.4
- RUBY VERSION: 2.4.1 (2016-04-26 patchlevel 112) [x86_64-darwin14]
- INSTALLATION DIRECTORY: /Users/danielkehoe/.rvm/gems/ruby-2.4.1@learn-rails
- USER INSTALLATION DIRECTORY: /Users/danielkehoe/.gem/ruby/2.3.0
- RUBY EXECUTABLE: /Users/danielkehoe/.rvm/rubies/ruby-2.4.1/bin/ruby
- EXECUTABLE DIRECTORY: /Users/danielkehoe/.rvm/gems/ruby-2.4.1@learn-rails/bin
- SPEC CACHE DIRECTORY: /Users/danielkehoe/.gem/specs
- SYSTEM CONFIGURATION DIRECTORY: /Users/danielkehoe/.rvm/rubies/ruby-2.4.1/etc
- RUBYGEMS PLATFORMS:
- ruby
- x86_64-darwin-14
- GEM PATHS:
- /Users/danielkehoe/.rvm/gems/ruby-2.4.1@learn-rails
- /Users/danielkehoe/.rvm/gems/ruby-2.4.1@global
.
www.dbooks.org
78 CHAPTER 9. GEMS
.
.
If you use RVM, gems are saved to a hidden .rvm folder in your user direc-
tory. A global subfolder contains the Bundler gem. If you’ve followed the
instructions in the “Get Started” chapter to install Rails, the project-specific
learn-rails subfolder contains the Rails gem. If you use Chruby or Rbenv in-
stead of RVM, your gems will be stored in a different location.
Run the gem which command and you’ll see where the gems live:
These are details you’ll never need to know, because Ruby on Rails handles it
for you.
You’ll never move or delete gems directly. Instead you’ll manage gems using
the Bundler utility. The key to Bundler is the Gemfile.
Gemfile
Every Rails application has a Gemfile. Earlier, I described Rails from the view-
point of the “gem hunter,” the developer who wants to assemble an application
from the best open source components he or she can find. To the gem hunter,
the Gemfile is the most important file in the application. It lists each gem that
the developer wants to use.
The Gemfile provides the information needed by the Bundler utility to manage
gems.
Bundler’s bundle install command reads the Gemfile, then downloads and
saves each listed gem to the hidden gem folder. Bundler checks to see if the
GEMFILE 79
gem is already installed and only downloads gems that are needed. Bundler
checks for the newest gem version and records the version number in the Gem-
file.lock file. Bundler also downloads any gem dependencies and records the
dependencies in the Gemfile.lock file. Between the Gemfile, with its list of
gems that will be used by the application, and the Gemfile.lock file, with its
list of dependencies and version numbers, you have a complete specification of
every gem required to run the application. More importantly, when other devel-
opers install your application, Bundler will automatically install all the gems
(including dependencies and correct versions) needed to run the application.
When you deploy the application to production for others to use, automated
deployment scripts (such as those used by Heroku) install all the required gems.
Bundler provides a bundle update command when we want to replace any
gems with newer versions. If you run bundle update, any new gem ver-
sions will be downloaded and installed and the Gemfile.lock file will be up-
dated. Be aware that updating gems can break your application, so only update
gems when you have time to test and resolve any issues. You can run bundle
outdated to see which gems are available in newer versions.
If you want to prevent your fellow developers (or yourself) from accidentally
updating gems, you can specify a gem version number for any gem in the Gem-
file. The Gemfile gives fine-grained control over rules for updating:
“Pessimistic” versioning needs some explanation. ~> 5.0.0 means use any
version greater than 5.0.0 and less than 5.1 (any patch version can be used).
~> 5.0 means use any version greater than 5.0 and less than 6.0 (any minor
version can be used).
www.dbooks.org
80 CHAPTER 9. GEMS
In general, during development we only lock down any gem versions in the
Gemfile if we know newer versions introduce problems.
Let’s take a look at the Gemfile created by the rails new command.
source 'https://rubygems.org'
git_source(:github) do |repo_name|
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
"https://github.com/#{repo_name}.git"
end
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
# Adds support for Capybara system testing and selenium driver
gem 'capybara', '~> 2.13'
gem 'selenium-webdriver'
end
group :development do
# Access an IRB console on exception pages or by using <%= console %> anywhere in the code.
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
# Spring speeds up development by keeping your application running in the background. Read mor
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
The file you see will be very similar. Some version numbers may be different
if a newer Rails version was released since this was written.
The first line, source ’https://rubygems.org’, directs Bundler to use
the rubygems.org server as a source for any gems.
Notice that the second uncommented line directs Bundler to use Rails and spec-
ifies a range of acceptable versions. In this case, the Gemfile indicates we can
use any version between 5.1.2 and 5.2.
In the Gemfile you’ll see the gems for a Rails default application, such as the
sqlite3 database gem, which we described earlier. Other gems are commented
out (the lines begin with the # character). These are suggestions and we can
ignore them or remove them.
We won’t use a database for our application but we’ll keep the gem ’sqlite3’
entry. Configuring Rails for no database is complicated; it is easier to keep the
sqlite3 gem and not use it.
If you are developing your application on a computer using the Linux operating
system, you may need to uncomment and use the statement gem ’therubyracer’,
platforms: :ruby. Linux doesn’t have a built-in JavaScript interpreter so
you must install Node.js in your environment or else add the therubyracer gem
www.dbooks.org
82 CHAPTER 9. GEMS
to each project Gemfile. For help, see Install Ruby on Rails - Ubuntu.
It’s wise to specify the Ruby version we’re using. This is needed for automated
deployment scripts such as those used by Heroku. We can add that to the
Gemfile:
ruby '2.4.1'
If you add the Ruby version and remove the extra clutter in the Gemfile it will
look like this:
source 'https://rubygems.org'
ruby '2.4.1'
gem 'rails', '~> 5.1.2'
# Rails defaults
gem 'sqlite3'
gem 'puma', '~> 3.7'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
group :development, :test do
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'capybara', '~> 2.13'
gem 'selenium-webdriver'
end
group :development do
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end
Try it now. Replace the Gemfile with the simplified code above.
Adding Gems
I’ve identified several gems that will be useful for our tutorial application.
ADDING GEMS 83
• Ruby Toolbox
• RubyFlow
• various blog posts
• example code and starter apps on GitHub
• recommendations from colleagues
We’re adding these gems at the beginning of our development process since
we already know which gems we’ll need. On a real project, you’ll often dis-
cover useful gems and add them to the Gemfile during the ongoing process of
development.
Here are gems we’ll add to the Gemfile:
Versions of Rails prior to Rails 5.1 included the jquery-rails gem by default. The
gem was dropped from Rails 5.1. We’ll add the jquery-rails gem because it is
required by the Bootstrap front-end framework.
www.dbooks.org
84 CHAPTER 9. GEMS
Open your Gemfile and replace the contents with the following:
source 'https://rubygems.org'
ruby '2.4.1'
gem 'rails', '~> 5.1.2'
# Rails defaults
gem 'sqlite3'
gem 'puma', '~> 3.7'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
group :development, :test do
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'capybara', '~> 2.13'
gem 'selenium-webdriver'
end
group :development do
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end
# learn-rails
gem 'bootstrap-sass'
gem 'gibbon'
gem 'high_voltage'
gem 'jquery-rails'
group :development do
gem 'better_errors'
gem 'rails_layout'
end
Notice that we’ve placed two gems inside a “group.” Specifying a group for
development or testing ensures a gem is not loaded in production, reducing the
application’s memory footprint. Rails let you specify groups for development,
test, or production.
ABOUT THE RAILS VERSION 85
$ bundle install
The bundle install command will download the gems from the rubygems.org
server and save them to a hidden directory that is managed by the RVM gemset
you’ve specified.
We’ll see all the gems and their dependencies:
www.dbooks.org
86 CHAPTER 9. GEMS
You can use your text editor to view the contents of Gemfile.lock and you will
see a detailed listing of every gem and each dependency, with version numbers.
There’s no reason to edit a Gemfile.lock file; if it is ever in error, delete it and
run bundle install to recreate it.
Run gem list to see all the gems that are loaded into the development envi-
ronment:
$ gem list
The list of gems loaded in the environment is the same as the list specified in the
Gemfile.lock file. Here’s how it works. RVM makes a place for the gems to be
stored (the RVM gemset); the Gemfile lists the gems you want to use; bundle
install reads the Gemfile and installs the gems into the RVM gemset; the
Gemfile.lock file records dependencies and version numbers; and gem list
shows you the gems that are in the gemset and available for use.
Troubleshooting
If your development environment is set up correctly, there should be no dif-
ficulty installing gems with the bundle install command. If your devel-
opment environment is not set up correctly, you may see error messages when
GIT 87
Bundler attempts to install the Nokogiri gem. Nokogiri is often needed by other
gems (it is a dependency of some gems) and Nokogiri can become a problem to
install. Unlike most gems that are written in pure Ruby, parts of Nokogiri are
written in the C language and must be compiled using system tools that vary
with different operating systems. If you get an error while installing gems, and
the message says, “An error occurred while installing nokogiri,” ask for help
on Stack Overflow.
Git
Let’s commit our changes to the Git repository and push to GitHub:
$ git add -A
$ git commit -m "add gems"
$ git push origin master
After your first use of git push origin master, you can use the shortcut
git push.
If you get a message:
fatal: Not a git repository (or any of the parent directories): .git
It indicates you are in a folder that has not been initialized with Git. You are
probably not in your project directory. Use the Unix command pwd to see
where you are.
If you get a message:
www.dbooks.org
88 CHAPTER 9. GEMS
It shows that you can’t connect to GitHub to push the changes. To investigate,
enter:
It is not absolutely necessary to use GitHub for this tutorial. We’re only using
it so you’ll be familiar with the workflow of professional development.
We’re ready to configure the application.
Chapter 10
Configure
Rails is known for its “convention over configuration” guiding principle. As
applied, the principle reduces the need for many configuration files. It’s not
possible to eliminate all configuration files, however. Many applications re-
quire configuration of settings such as email account credentials or API keys
for external services.
In our tutorial application, we’ll need to store an API key to access MailChimp,
which we’ll use to add visitors’ email addresses to a mailing list. We’ll also
need to store credentials so we can send email using the SendGrid transactional
email service.
Rails provides the config/secrets.yml file for our configuration settings. Any
variable that is set in the config/secrets.yml file can be used elsewhere in our
Rails application, providing a single location for all our configuration variables.
Configuration Security
GitHub is a good place to store and share code. But when your repos are public,
they are not a good place for secret account credentials. In fact, any shared Git
repository, even a private repo, is a bad place to store email account credentials
89
www.dbooks.org
90 CHAPTER 10. CONFIGURE
Videos
If you have subscribed, now’s a good time to watch:
$ echo $SHELL
/bin/bash
If you see /bin/bash, that’s great! If not, you may have to do some research
to find out how to set environment variables in your shell.
You might be surprised to see a dollar sign in the command. You don’t type the
first dollar sign (it is just the convention that indicates you are entering a Unix
command). You’ll type echo $SHELL to ask the operating system to show the
variable SHELL. The dollar sign in the command tells Unix to return a variable
named SHELL. Try typing echo SHELL without the dollar sign and you’ll see
echo just displays what you type.
When you open a console window, the bash shell reads a configuration file in
your user home directory. You can use a Unix command to list all the files in
your user home directory (the ~ “tilde” character represents your home direc-
tory):
$ ls -1pa ~
.
.
.
.bash_profile
.
.
.
On the Mac, you’ll see .bash_profile. On Linux systems, you’ll see .bashrc.
www.dbooks.org
92 CHAPTER 10. CONFIGURE
$ atom ~/.bash_profile
In Unix, the squiggle (tilde) character is a shortcut to your user home folder.
Open either file and you’ll likely find a command such as:
export PATH=~/.bin:$PATH
That is a command that sets the PATH environment variable. The command
might not be exactly the same but it is likely you will see some export com-
mands.
You can add the environment variables anywhere in the file. For convenience,
add the environment variables near the end of the file, above any existing
EXPORT statement.
You should use quotes to surround configuration values (credentials) in the
.bash_profile or .bashrc files.
If you don’t have a .bash_profile or .bashrc file in your user home directory,
you can create one.
SET ENVIRONMENT VARIABLES 93
• SENDGRID_USERNAME
• SENDGRID_PASSWORD
• MAILCHIMP_API_KEY
• MAILCHIMP_LIST_ID
• OWNER_EMAIL
SendGrid
You’ll need your SendGrid username and password. The credentials are the
same you use to sign in to the SendGrid website.
Add your SendGrid username and password to your .bash_profile or .bashrc
file:
export SENDGRID_USERNAME="example"
export SENDGRID_PASSWORD="secret"
www.dbooks.org
94 CHAPTER 10. CONFIGURE
MailChimp
When visitors sign up to receive a newsletter, we’ll add them to a MailChimp
list. Add an environment variable for the MailChimp API key: MAILCHIMP_API_KEY.
Sign in to MailChimp to get your API key. Click your name at the top of the
navigation menu, then click “Account.” Click “Extras,” then “API keys.” You
have to generate an API key; MailChimp doesn’t create one automatically. The
MailChimp API key is a long string of characters like a secret code that works
like a password. Enter it in your .bash_profile or .bashrc file:
export MAILCHIMP_API_KEY="Your_MailChimp_API_Key"
You’ll need to create a MailChimp mailing list in preparation for our “Mailing
List” chapter. Have you already created a MailChimp mailing list? If not, the
MailChimp “Lists” page has a button for “Create List.” The list name and other
details are up to you.
We’ll need the MAILCHIMP_LIST_ID for the mailing list you’ve created. To
find the list ID, on the MailChimp “Lists” page, click the “down arrow” for a
menu and click “Settings.” At the bottom of the “List Settings” page, you’ll
find the unique ID for the mailing list.
export MAILCHIMP_LIST_ID="Your_List_ID"
Owner Email
You’ll send email messages to this address when a visitor submits a contact
request form. Set OWNER_EMAIL with an email address where you receive
mail.
SET ENVIRONMENT VARIABLES 95
export OWNER_EMAIL="[email protected]"
Enter an email address and your environment variables will be set up with the
site owner email address.
Troubleshooting
Check that the SendGrid user name is set in your Unix environment variables:
$ echo "$SENDGRID_USERNAME"
You should see your SendGrid user name in the console response. Make sure
you’ve used underscores consistently and you’ve used SENDGRID_USERNAME
not SENDGRID_USER_NAME.
If you have trouble, remember to close and reopen your terminal to make sure
the environment includes any recent changes.
On Linux, if you’ve entered the environment variables in your .bashrc file but
they don’t seem to work, try setting them in your .bash_profile file instead.
If you’ve set up Unix environment variables but echo "$SENDGRID_USERNAME"
doesn’t return the correct variable in the console, you may have a problem with
the way you’ve set Unix environment variables. Most computers use the bash
shell and you can set environment variables in your .bash_profile or .bashrc
files. But not every system is alike. If it seems Unix environment variables are
not working, you may have to find a colleague who can help you troubleshoot.
www.dbooks.org
96 CHAPTER 10. CONFIGURE
If you are having problems, you can continue with the tutorial and add the
credentials directly to the config/secrets.yml file.
# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# shared:
# api_key: a1B2c3D4e5F6
development:
email_provider_username: <%= ENV["SENDGRID_USERNAME"] %>
email_provider_password: <%= ENV["SENDGRID_PASSWORD"] %>
domain_name: example.com
mailchimp_api_key: <%= ENV["MAILCHIMP_API_KEY"] %>
mailchimp_list_id: <%= ENV["MAILCHIMP_LIST_ID"] %>
owner_email: <%= ENV["OWNER_EMAIL"] %>
secret_key_base: very_long_random_string
test:
secret_key_base: very_long_random_string
production:
THE SECRETS FILE 97
Be sure to use spaces, not tabs. Make sure there is a space after each colon
and before the value for each entry or you will get a message “Internal Server
Error: mapping values are not allowed” when you start the web server.
You used quotes to surround configuration values in the .bashrc or .bash_profile
files. Here, in the config/secrets.yml file, you don’t need quotes when you are
importing Unix environment variables.
Domain Name
We’ll need a domain name when we configure email for delivery in production.
For development, use example.com. If you have your own domain name, you
can use that instead. There’s no need to keep the domain_name configuration
variable secret, so we don’t need to set it in a Unix environment variable.
You can decide for yourself if the owner_email variable really needs to be
secret. Just for caution, I’m suggesting you set it as a Unix environment vari-
able.
www.dbooks.org
98 CHAPTER 10. CONFIGURE
file. If you only reveal the SECRET_KEY_BASE used for development or test-
ing, and no one can access your development machine, no useful secrets will
be revealed in your GitHub repo.
When you deploy to Heroku, the config/secrets.yml file must be in your Git
repository. For that reason, I suggest you save the file in your Git repo and keep
your secrets safe by using environment variables.
Troubleshooting
Remember, in YAML files (with the file extension .yml), indentation is required
(your application will break without it).
Be sure to use spaces, not tabs. Make sure there is a space after each colon and
before the value for each entry.
If you have trouble setting Unix environment variables, you can add credentials
directly to the config/secrets.yml file. If you do so, you should not check the
file into Git until you’ve deleted the secrets from the file.
Replace the following if you are troubleshooting:
development:
email_provider_username: <%= ENV["SENDGRID_USERNAME"] %>
email_provider_password: <%= ENV["SENDGRID_PASSWORD"] %>
with:
development:
email_provider_username: example
email_provider_password: 's#cr*t'
In a YAML file, you do not need quotes unless your string contains special
characters. If your password contains any of these characters you should sur-
round the string with single quotes:
SECRET KEY BASE 99
Again, DON’T CHECK THE FILE INTO GIT if you’ve hardcoded your cre-
dentials directly in the config/secrets.yml file.
The article Rails Environment Variables shows alternatives to using Unix en-
vironment variables, if for any reason you cannot set environment variables on
your machine.
$ rails secret
very_long_random_string
export SECRET_KEY_BASE="very_long_random_string"
www.dbooks.org
100 CHAPTER 10. CONFIGURE
Configure Email
Email messages are visible in the console and the log file when you test the
application. If you don’t want to actually send email, you can skip this step.
But it’s more fun when your application can actually send email.
You can learn more in the article Send Email with Rails.
config.assets.debug = true
config.action_mailer.smtp_settings = {
address: "smtp.sendgrid.net",
port: 587,
domain: Rails.application.secrets.domain_name,
authentication: "plain",
enable_starttls_auto: true,
user_name: Rails.application.secrets.email_provider_username,
password: Rails.application.secrets.email_provider_password
}
# ActionMailer Config
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.delivery_method = :smtp
config.action_mailer.raise_delivery_errors = true
# Send email in development mode?
config.action_mailer.perform_deliveries = true
You can use port 25, 587, or 2525 (some ISPs restrict connections on port 25).
It’s important to add these changes in the body of the configuration file, before
the end keyword. The order isn’t important but don’t add the configuration
statements after the end keyword.
Notice that we are using configuration variables that are set in the config/secrets.yml
file:
www.dbooks.org
102 CHAPTER 10. CONFIGURE
• Rails.application.secrets.email_provider_username
• Rails.application.secrets.email_provider_password
We could “hard code” a username and password here but that would expose
confidential data if your GitHub repository is public. Using configuration vari-
ables that are set in the config/secrets.yml file keeps your secrets safe.
Again, if you need to troubleshoot, you can enter the SendGrid username and
password directly in this file instead of the configuration variables. But for
security, don’t commit to Git with the password hardcoded in this file.
If you want to send real messages when you test the application in development
mode, modify the file config/environments/development.rb.
After the code you just added, add the statement:
This changes the configuration to send email when you’re working on the ap-
plication.
Make sure any code you’ve added to the config/environments/development.rb
file is placed before the final end keyword. If you add code after the final end
keyword, your application will fail with errors when you start the web server.
Later, after we add a contact form to the tutorial application, the application
will be ready to send email messages.
GIT 103
Git
Make sure you’re in your application root directory.
Let’s commit our changes to the Git repository and push to GitHub:
$ git add -A
$ git commit -m "add configuration"
$ git push
www.dbooks.org
104 CHAPTER 10. CONFIGURE
Chapter 11
$ rails server
105
www.dbooks.org
106 CHAPTER 11. STATIC PAGES AND ROUTING
<h1>Hello World</h1>
Refresh the browser window and you’ll see the “Hello World” message.
The Rails application server looks for any pages in the public folder by default.
If no filename is specified in the URL, the server will attempt to respond with a
file named index.html. This is a convention that dates to 1993; if no filename
was specified, one of the first web servers ever built (the NCSA httpd server)
would return a list of all files in the directory, unless a file named index.html
was present. Since then, index.html has been the default filename for a home
page.
Routing Error
What happens when no file matches the requested web address?
Enter the URL http://localhost:3000/about.html in your browser.
You’ll see an error page that shows a routing error.
If you are using Cloud9, add “/about.html” to the URL in the preview browser
window.
<h1>About</h1>
INTRODUCING ROUTES 107
Introducing TDD
Introducing Routes
The guiding principle of “convention over configuration” governs Rails rout-
ing. If the web browser requests a page named “index.html”, Rails will deliver
the page from the public folder by default. No configuration is required. But
what if you want to override the default behavior? Rails provides a configura-
tion file to control web request routing.
If you’ve got only one terminal window open, you’ll have to stop the Rails
server with Control-c to get your terminal prompt. Here is where it is helpful
to have two terminal sessions going in different tabs.
Let’s set the “About” page as the home page.
Open the file config/routes.rb. Remove all the comments and replace the file
with this:
www.dbooks.org
108 CHAPTER 11. STATIC PAGES AND ROUTING
Rails.application.routes.draw do
root to: redirect('/about.html')
end
This snippet of Rails routing code takes any request to the application root
(http://localhost:3000/) and redirects it to the about.html file (which is ex-
pected to be found in the public folder).
There is no need to restart your application server to see the new behavior. If
you need to start the server:
$ rails server
Later in the tutorial we’ll create a new “About” page using a different approach.
www.dbooks.org
110 CHAPTER 11. STATIC PAGES AND ROUTING
Chapter 12
111
www.dbooks.org
112 CHAPTER 12. REQUEST AND RESPONSE
and the web browser, but even so, an initial request-response cycle delivers the
page that sets up the stream.
We can reduce the mystery of how the web works to its simplest components
when we investigate the request-response cycle. We’ll see that everything that
happens in a web application takes place within the flow of the request-response
cycle.
Let’s look at the request-response cycle.
$ rails server
Developers use various web browsers during development. I’ll provide instruc-
tions for Chrome, since it is the most popular. Even if you prefer Mozilla Fire-
fox or Apple Safari, try this in Chrome, so you can follow along with the text.
Start our investigation by putting Chrome into “Incognito Mode” with Command-
Shift-N (on a Mac). On Linux, use Ctrl-Shift-N to get in incognito mode with
INVESTIGATING THE REQUEST RESPONSE CYCLE 113
Chrome. Alternatively, you can clear the browser cache. This clears any files
that were previously cached by the browser.
The Developer Tools view is your primary diagnostic tool for front-end (browser-
based) development, including CSS and JavaScript.
In Chrome on macOS, press Command-Option-I to open the Developer Tools
View in a section of the browser window. Alternatively, you can find the menu
item under View/Developer/Developer Tools.
In Chrome on Windows or Linux platforms, press Shift-Ctrl-I or select Menu/Tools/Develope
Tools.
Initiate the request-response cycle by visiting the “About” page at http://localhost:3000/abou
In the Developer Tools view, under the Network tab, you’ll see files received
by the browser from the web server. There is only one: “about.html”. This is
the file that the browser evaluates to display a web page.
Be sure to select the Network tab in the Developer Tools view.
Click the “about.html” file icon. Then click the tab “Headers.” The diagnos-
tic window shows the entire request sent to the server and the entire response
received by the browser.
Under the heading “General,” you can see the request is composed of:
www.dbooks.org
114 CHAPTER 12. REQUEST AND RESPONSE
You can see the HTML sent to the browser by clicking the Preview or Response
tabs in the view under the Network tab.
Here’s the point of the exercise: The browser’s Developer Tools view shows all
the data exchanged between the browser and server. You’re looking at every-
thing that passes through the plumbing.
The browser’s Developer Tools view doesn’t show you what happens on the
server. For that, go to the server logs or the console window.
HOW THE BROWSER WORKS 115
Notice how the diagnostic messages in the console window match the headers
in the browser Developer Tools view. The browser’s “Request Method:GET”
matches the server’s “Started GET.”
Notice there are no console log messages for pages delivered from the public
folder.
Soon we’ll see much more in the console window, after we’ve built a dynamic
web page that is assembled by the application server.
When the web browser receives an HTML file, it creates an internal represen-
tation of the page in computer memory, called the Document Object Model
(DOM). It provides a structural representation of the document. The DOM
works like an API for HTML documents, allowing you to modify the content
and visual presentation of the page by using JavaScript.
Later in the tutorial, we’ll see how a JavaScript library such as jQuery can
be used to do things like hiding or revealing HTML elements on a page by
manipulating the DOM.
www.dbooks.org
116 CHAPTER 12. REQUEST AND RESPONSE
Rendering
Each time the DOM changes, the browser engine converts the DOM to a visual
representation of the page and renders it in the browser window.
Knowing about the DOM will help you understand what happens in the browser
when it receives a web response. And understanding the DOM will help you
work with JavaScript for front-end programming. But in this book, our focus
is on building a server-side web application in Rails. Let’s see how a Rails
application responds to a web request.
Video Option
This eight minute video introduces the model–view–controller concept:
You learned earlier that, from the perspective of a software architect, Rails is
organized to conform to the model–view–controller software design pattern.
This enforces “separation of concerns” to keep code manageable and orga-
nized. The MVC design pattern is optimal for web applications and is a central
organizing principle for Rails.
The MVC design pattern originated in the design of desktop applications. “Model”
classes manipulated data; “view” classes created the user interface; and a “con-
troller” class responded to user interaction.
Some computer scientists feel the architecture of web applications doesn’t quite
match the original MVC design pattern of desktop applications. We can see
the reason for the quibble in the next diagram. The diagram shows the MVC
architecture as part of the Rails software stack.
At the base of the stack is the web browser. A request flows upward through the
layers and encounters the router which dispatches the request to an appropriate
controller.
In a Rails application, there is a single routing file, config/routes.rb, and mul-
tiple controllers, models, and views.
Considering the importance of the router, perhaps we should call our Rails
architecture the RCMV, or Routing-Controller-Model-View, pattern. Despite
the quibble about nomenclature, the architecture is well understood and used
by all Rails developers.
Here’s the step-by-step walk-through of what happens.
When the web browser makes a request, a router component will check the
config/routes.rb file and determine which controller should handle the request,
based on the web address and HTTP protocol. The controller will obtain any
needed data from a model. After obtaining data, the controller will render a
response combining data from the model with a view component that provides
markup and layout. The response is an HTML file that the controller assembles
for the browser to display.
The model, view, and controller are files you create containing Ruby code.
www.dbooks.org
118 CHAPTER 12. REQUEST AND RESPONSE
Each file has a certain structure and syntax based on foundation model, view,
and controller classes defined in the Rails framework. The model, view, and
controller classes you create will inherit behavior from parent classes that are
part of the framework, so you will have less code to write yourself.
In most Rails applications, a model obtains data from a database, though some
models obtain data from a remote connection to another server. For example, a
User model might retrieve a user name and email address from a local database.
A User model could also obtain a user’s recent tweets from Twitter or a user’s
hometown from Facebook. The controller can obtain data from more than one
model if necessary.
A controller can have more than one action. For example, a User controller
might have actions to display a list of users, or add or delete a user from a
list. The config/routes.rb file matches a web request to a controller action. In
the software architects’ terminology, each action is a method of the controller
class. We use the terms action and method interchangeably when we talk about
a Rails controller; to be precise, controller actions are implemented as methods.
In practice, Rails developers try to limit controllers to seven standard actions:
index, show, new, create, edit, update and destroy actions. A con-
troller that offers these actions is said to be “RESTful” (a term that refers to
representational state transfer, another software design abstraction). It’s not
important to understand the abstract principles of RESTful design; recogniz-
ing the term and knowing that Rails controllers have seven standard actions is
sufficient for beginners.
A view file combines Ruby code with HTML markup. Typically there will be a
view file associated with each controller action that displays a page. An index
view might show a list of users. A “show” view might provide details of a user’s
profile. View files look much like ordinary HTML files but typically contain
data in the form of Ruby variables. Often you’ll see Ruby statements such as
blocks that iterate through lists to create tables. Following the “separation of
concerns” principle, it is considered good practice to limit Ruby code in view
files to only displaying data; anything else belongs in a model.
Not every controller action has its own view file. In many controllers, on com-
REMOVE THE ABOUT PAGE 119
pletion, the destroy action will redirect to the index view, and create will
redirect to either show or new.
This conceptual overview will be easier to grasp when you actually see the code
for a model, view, and controller. We’ll create model, view, and controller files
in the next chapter.
$ rm public/about.html
Earlier, we set up the config/routes.rb file. You can leave it in place. We’ll
change it in the next chapter.
Now we’ll look at ways to implement the home page using the full power of
Rails.
www.dbooks.org
120 CHAPTER 12. REQUEST AND RESPONSE
www.dbooks.org
122 CHAPTER 12. REQUEST AND RESPONSE
User Story
We’ll plan our work with a user story:
*Birthday Countdown*
As a visitor to the website
I want to see the owner's name
I want to see the owner's birthdate
I want to see how many days until the owner's next birthday
In order to send birthday greetings
This silly home page will help us explore Rails and learn about the Ruby lan-
guage.
Our goal is to build a practical web application that you can really use. Later
we’ll replace this silly home page with a useful web page that encourages visi-
tors to sign up for a mailing list.
123
www.dbooks.org
124 CHAPTER 13. DYNAMIC HOME PAGE
What about a name for the controller that will render our home page? How
about “Home controller” or “Welcome controller?” Those names are accept-
able. But if we consider our user story, the name “Visitors controller” is best.
A visitor is the actor, so “Visitors controller” is appropriate:
NAMING CONVENTIONS 125
Later we’ll see this is a good choice because we’ll create a Visitor model to
handle data about the website visitor. In Rails, there is often a model with
the same name as a controller (though a controller can use data from multiple
models).
Naming Conventions
Rails is picky about class names and filenames. That’s because of the “conven-
tion over configuration” principle. By requiring certain naming patterns, Rails
avoids complex configuration files.
Before we look at class and filename conventions, here’s a note about typo-
graphic terminology:
When you write code, you’ll follow rules for class names:
www.dbooks.org
126 CHAPTER 13. DYNAMIC HOME PAGE
Here are the rules for filenames. They are always lowercase, with words sepa-
rated by underscores (snake_case):
• the model filename matches the model class name, but lowercase, for
example app/models/visitor.rb
• the controller filename matches the controller class name, but snake_case,
for example app/controllers/visitors_controller.rb
• the views folder matches the model class name, but plural and lowercase,
for example app/views/visitors
At first the rules may seem arbitrary, but with experience they will make sense.
The rule about no capital letters or spaces in filenames has its origins in com-
puter antiquity.
If you stray from these naming conventions, you’ll encounter unexpected prob-
lems and frustration.
Routing
We’ll create the route before we implement the model and controller.
Open the file config/routes.rb. Replace the contents with this:
Rails.application.routes.draw do
root to: 'visitors#new'
end
MODEL 127
$ rails server
Model
Most Rails models obtain data from a database. When you use a database,
you can use the rails generate model command to create a model that
inherits from the ActiveRecord class and knows how to connect to a database.
To keep things simple, our tutorial application doesn’t need a database. Instead
of inheriting from ActiveRecord, we create a Ruby class with methods that
return the owner’s name, birthdate, and days remaining until his birthday. This
simple class provides an easy introduction to Ruby code.
Create a file app/models/owner.rb (don’t include the colon punctuation that
follows):
www.dbooks.org
128 CHAPTER 13. DYNAMIC HOME PAGE
class Owner
def name
name = 'Foobar Kadigan'
end
def birthdate
birthdate = Date.new(1990, 12, 22)
end
def countdown
today = Date.today
birthday = Date.new(today.year, birthdate.month, birthdate.day)
if birthday > today
countdown = (birthday - today).to_i
else
countdown = (birthday.next_year - today).to_i
end
end
end
This is your first close look at Ruby code. The oddest thing you’ll see is the
owner’s name, “Foobar Kadigan.” Everything else will make sense with a bit
of explanation.
Keep in mind that we are using a text file to create an abstraction that we can
manipulate in the computer’s memory. Software architects call these abstrac-
tions objects. In Ruby, everything we create and manipulate is an object. To
distinguish one object from another, we define it as a class, give it a class name,
and add behavior in the form of methods.
The first line class Owner defines the class and assigns a name. At the very
end of the file, the end keyword completes the class definition.
We define three methods, starting with def (for “method definition”) and end-
ing with end.
Each method contains simple Ruby code that assigns data to a variable. Later,
we’ll retrieve the data for use in our view file by instantiating the class and call-
ing a method. Don’t be discouraged by the software architects’ terminology;
the concepts are simple and we’ll soon see everything in action.
Ruby makes it easy for a method to return data when called; the value assigned
by the last statement will be delivered when the method is called.
Looking more closely at the Ruby code inside the method definitions, you’ll
see Ruby uses the = (equals) sign to assign values to a variable. The variable is
named on the left side of the equals sign; a value is assigned on the right side.
We call the equals sign an assignment operator.
We can assign any value to a variable, including a string (a series of characters
that can be a word or name) such as “Foobar Kadigan.” Ruby recognizes a
string when characters are enclosed in single or double quotes. Not surpris-
ingly, a number also can be assigned to a variable, either a whole number (an
integer) or a decimal fraction (a float).
More interestingly, any Ruby object can be assigned to a variable. That helps
us “move around” any object very easily, giving us access to the object’s class
methods anywhere we use the variable. We can create our own objects, as we
have by creating the Owner class. Or we can use the library of objects that
are supplied with Ruby. Ruby’s prefabricated objects are defined by the Ruby
API (application programming interface); essentially the API is a catalog of
prebuilt classes that are building blocks for any application. The Rails API
gives us additional classes that are useful for web applications. Learning the
syntax of Ruby code gets you started with Ruby programming; knowing the
API classes leads to mastery of Ruby.
The Date class is provided by the Ruby API. It is described in the Ruby API
reference documentation. The Date class has a Date.new method which in-
stantiates (creates) a new date when supplied with year, month, and day pa-
rameters. You can see this syntax when we assign Date.new(1990, 12,
22) to the birthdate variable.
www.dbooks.org
130 CHAPTER 13. DYNAMIC HOME PAGE
Note that Ruby has specific expectations about the syntax of numbers. The
Date.new(...) method expects integers. Imagine a September birthday.
You must use Date.new(1990, 9, 22). If you enter a date in the format
Date.new(1990, 09, 22), you’ll get a syntax error “Invalid octal digit”
when you test the application. Ruby expects numbers that begin with zero to
be octal numbers; you’ll get an error because octal numbers can’t contain the
digit “9.”
Our countdown method contains the most complex code in the class.
First, we set a variable today with today’s date. The Date.today method cre-
ates an object that represents the current date. When the Date.today method
is called, Ruby gets the current date from the computer’s system clock.
Next we create a birthday variable and assign a new date that combines to-
day’s year with the month and day of the birthdate. This gives us the date
of Foobar Kadigan’s birthday this year.
The Date class can perform complex calendar arithmetic. The variables birthdate
and today are instances of the Date class. We can use a greater-than operator
to determine if Foobar Kadigan’s birthday is in the future or the past.
The if ... else ... end structure is a conditional statement. If the
birthday is in the future, we subtract today from birthday to calculate the
number of days remaining until the owner’s birthday, which we assign to the
countdown variable.
If the birthday has already passed, we apply a next_year method to the birth-
day to get next year’s birthday. Then we subtract today from birthday.next_year
to calculate the number of days remaining until the owner’s birthday, which we
assign to the countdown variable.
The result might be fractional so we use the utility method to_i to convert
the result to a whole number (integer) before assigning it to the countdown
variable.
This shows you the power of programming in Ruby. Notice that I needed 16
paragraphs and over 600 words to explain 15 short lines of code. We used only
VIEW 131
seven Ruby abstractions but they represent thousands of lines of code in the
Ruby language implementation. With knowledge of Ruby syntax and the Ruby
API, a few short lines of code in a text file gives us amazing ability.
In an upcoming chapter, we’ll look more closely at the syntax and keywords of
the Ruby language. But without knowing more than this, we can build a simple
web application.
Let’s see how we can put this functionality to use on a web page.
View
The Owner model provides the data we want to see on the Home page.
We’ll create the markup and layout in a View file and add variables that present
the data.
View files go in folders in the app/views/ directory. In a typical application,
one controller can render multiple views, so we make a folder to match each
controller. You can make a new folder using your file browser or text editor. Or
use the Unix mkdir command:
$ mkdir app/views/visitors
<h3>Home</h3>
<p>Welcome to the home of <%= @owner.name %>.</p>
<p>I was born on <%= @owner.birthdate %>.</p>
<p>Only <%= @owner.countdown %> days until my birthday!</p>
We’ve created a visitors/ folder within the app/views/ directory. We have only
a single new view but if we had more views associated with the Visitors con-
troller, they’d go in the app/views/visitors/ folder.
www.dbooks.org
132 CHAPTER 13. DYNAMIC HOME PAGE
We name our View file new.html.erb, adding the .erb file extension so that
Rails will use the ERB templating engine to interpret the markup.
There are several syntaxes that can be used for a view file. In this tutorial, we’ll
use the ERB syntax that is most commonly used by beginners. Some experi-
enced developers prefer to add gems that provide the Haml or Slim templating
engines. As you might guess, a View that uses the Haml templating syntax
would be named new.html.haml.
Our HTML markup is minimal, using only the <h3> and <p> tags. The only
ERB markup we add are the <%= ... %> delimiters. This markup allows us
to insert Ruby code which will be replaced by the result of evaluating the code.
In other words, <%= @owner.name %> will appear on the page as Foobar
Kadigan.
You may have noticed that we refer to the Owner model with the variable
@owner. It will be clear when we create the Visitors controller why we use
this syntax (a variable name that begins with the @ character is called an in-
stance variable).
Obviously, if all we wanted to do was include the owner’s name on the page,
it would be easier to simply write the text. The Rails implementation becomes
useful if the name is retrieved from a database or created programmatically.
We can better see the usefulness of the Owner model when we look at the use of
<= @owner.countdown %>. There is no way to display a calculation using
only static HTML, so Rails gives us a way to display the birthday countdown
calculation.
If you’re a programmer, you might wonder why we only output the variable on
the page. Since we can use ERB to embed any Ruby code, we could perform
the calculation right on the page by embedding <%= (Date.new(today.year,
@owner.birthdate.month, @owner.birthdate.day) - Date.today).to_i
%>. If you’ve used JavaScript or PHP, you may have performed calculations
like this, right on the page. Rails would allow us to do so, but the practice
violates the “separation of concerns” principle that encourages us to perform
complex calculations in a model and only display data in the view.
CONTROLLER 133
Before we can display the home page, we need to create the Visitors controller.
Controller
The Visitors controller is the glue that binds the Owner model with the Visi-
torsController#new view.
Note: When we refer to a controller action, we use the notation “VisitorsCon-
troller#new,” joining the controller class name with the action (method) that
renders a page. In this context, the # character is only a documentation con-
vention.
Note: VisitorsController will be the class name and visitors_controller.rb
will be the filename. The class name is written in camelCase (with a hump in
the middle, like a camel) so we can combine two words without a space.
Unix commands get messy when filenames include spaces so we create a file-
name that combines two words with an underscore (sometimes called “snake_case”).
Create a file app/controllers/visitors_controller.rb (don’t include the colon
punctuation that follows):
def new
@owner = Owner.new
end
end
www.dbooks.org
134 CHAPTER 13. DYNAMIC HOME PAGE
def new
@owner = Owner.new
render 'visitors/new'
end
end
Scaffolding
This tutorial aims to give you a solid foundation in basic concepts. The model–
view–controller pattern is one of the most important. I’ve found the best way
to understand model–view–controller architecture is to create and examine the
model, view, and controller files.
As you continue your study of Rails, you’ll find other tutorials that use the
scaffolding shortcut. For example, Rails Guides: Getting Started with Rails
includes a section “Getting Up and Running Quickly with Scaffolding” which
shows how to use the rails generate scaffold command to create model,
view, and controller files in a single operation. Students often use scaffolding
to create simple Rails applications.
In practice, I’ve observed that working Rails developers seldom use scaffold-
ing. There’s nothing wrong with it; it just seems that scaffolding doesn’t offer
much that can’t be done as quickly by hand.
$ rails server
www.dbooks.org
136 CHAPTER 13. DYNAMIC HOME PAGE
It’s a very simple web page but it uses Ruby to calculate the countdown to the
birthday. And the underlying code conforms to the conventions and structure
of Rails.
Git
At this point, you might have the Rails server running in your console window.
We’re going to run a git command in the console now.
You might think you have to enter Control-c to shut down the server and get
the command prompt. But that’s not necessary. You can open more than one
GIT 137
console view. Your terminal application lets you open multiple windows or
tabs. If you open multiple tabs, you can easily switch between console views
without using a lot of screen real estate. If you haven’t tried it, now is a good
time. On the Mac, Command+t opens a new tab in the terminal application. It
is convenient to have a console tab open for the server and another for various
Unix commands.
Let’s commit our changes to the Git repository and push to GitHub:
$ git add -A
$ git commit -m "dynamic home page"
$ git push
www.dbooks.org
138 CHAPTER 13. DYNAMIC HOME PAGE
Chapter 14
Troubleshoot
In the last chapter, we built a dynamic home page and learned about the model–
view–controller architecture of Rails. There was a lot to learn, but the code was
simple, and I hope it worked the first time you tried it.
Before we do any more work on our tutorial application, we need to learn about
troubleshooting and debugging. As a software developer, you’ll spend a lot of
time with code that doesn’t work. You’ll need tools and techniques to diagnose
problems.
Git
In this chapter we’ll make changes to the application just for troubleshooting.
Before you get started, make sure the work you’ve done is committed to your
git repository. Use the git status command to check:
$ git status
139
www.dbooks.org
140 CHAPTER 14. TROUBLESHOOT
On branch master
nothing to commit, working directory clean
If git status reports any uncommitted changes, go back to the last step in
the previous chapter and commit your work to the git repository before con-
tinuing. At the end of this chapter, we’re going to throw away the work we’ve
done in this chapter. We don’t want to accidentally throw away work from the
previous chapter so make sure it is committed to the repository.
$ irb
>>
The command irb launches the program and displays a prompt that shows
your Ruby version, a line number, and an arrow. I’ll just show a simple prompt
in the examples, instead.
If you enter a valid Ruby expression, the interpreter will display the result of
evaluating the expression.
Try simple arithmetic:
INTERACTIVE RUBY SHELL 141
>> n = 2
=> 2
>> n + 2
=> 4
Wow! You are using your computer for simple math. Maybe you can delete
the calculator app from your phone.
IRB will evaluate any Ruby expression and helps you quickly determine if
syntax and logic is correct.
>> n = 10
=> 10
>> if n < 10
>> puts "small"
>> else
?> puts "big"
>> end
big
=> nil
>>
www.dbooks.org
142 CHAPTER 14. TROUBLESHOOT
Quitting IRB
It can be very frustrating to find you are stuck inside IRB. Unlike most shell
commands, you can’t quit with Control-c. Enter Control-d or type exit to quit
IRB:
$ irb
>> exit
Beyond IRB
If you ask experienced Rails developers for help with IRB, they’ll often recom-
mend you switch to Pry. Pry is a powerful alternative to the standard IRB shell
for Ruby. As you gain experience, you might take a look at Pry to see what
the enthusiasm is all about. But for now, as a beginner trying out a few lines of
Ruby code, there’s no need to learn Pry.
RAILS CONSOLE 143
Rails Console
IRB only evaluates expressions that are defined in the Ruby API. IRB doesn’t
know Rails.
It’d be great to have a tool like IRB that evaluates any expression defined in the
Rails API. The tool exists; it’s called the Rails console. It is particularly useful
because it loads your entire Rails application. Your application will be running
as if the application was waiting to respond to a web request. Then you can
expose behavior of any pieces of the web application.
$ rails console
...
Loading development environment (Rails 5.x.x)
>>
The Rails console behaves like IRB but loads your Rails development environ-
ment. The prompt shows it is ready to evaluate an expression.
Let’s use the Rails console to examine our Owner model:
We’ve created a variable named myboss and created a new instance of the
Owner class. The Rails console responds by displaying the unique identifier it
uses to track the object. The identifier is not particularly useful, except to show
that something was created.
If you’re unsure about the difference between an instance and a class, we’ve
just seen that we can make one or more instances of a class by calling the
Owner.new method. When we specify the Owner class, the class definition is
loaded into the computer’s working memory (our development environment)
from the class definition file on disk. Then we can use the Owner.new method
to make one or more instances of the Owner class. Each instance is a unique
www.dbooks.org
144 CHAPTER 14. TROUBLESHOOT
object with its own data attributes but the same behavior as other objects in-
stantiated from its class.
Let’s assign the name of our boss to a variable called name:
We’re done for now. When we quit the Rails console or shut down the computer
the Owner class definition remains stored on disk but the instances disappear.
The bits that were organized to create the variable name will evaporate into the
ether.
Actually, the bits are still there, in the form of logic states in the computer’s
chips, but they have no meaning until another program uses them.
Enter Control-d or type exit to quit the Rails console.
The Rails console is a useful utility. It is like a handy calculator for your code.
Use it when you need to experiment or try out short code snippets.
Rails Logger
As you know, a Rails application sends output to the browser that makes a
web request. On every request, it also sends diagnostic output to the server
RAILS LOGGER 145
• log/development.log
• log/production.log
In development, everything written to the log file appears in the console win-
dow after you run the rails server command. Scrolling the console win-
dow is a good way to see diagnostics for every request.
Here’s what you see in the log after you visit the application home page:
You may have more than one console window open in the terminal application.
If you don’t see your log output in your terminal, check if you have tabs with
other windows.
Here’s the best part. You can add your own messages to the log output by using
the Rails logger. Let’s try it out.
Modify the file app/controllers/visitors_controller.rb:
def new
Rails.logger.debug 'DEBUG: entering new method'
@owner = Owner.new
Rails.logger.debug 'DEBUG: Owner name is ' + @owner.name
end
end
Visit the home page again and you’ll see this in the console output:
www.dbooks.org
146 CHAPTER 14. TROUBLESHOOT
If you really needed to do so, you could add a logger statement at every step in
the application. You could see how the application behaves, step by step. And
you could “print” the value of every variable at every step. You’ll never need
diagnostics at this level of detail in Rails, but the logger is extremely useful
when you are trying to understand unexpected behavior.
Let’s add logger statements to the Owner model. Modify the file app/models/owner.rb:
class Owner
def name
name = 'Foobar Kadigan'
end
def birthdate
birthdate = Date.new(1990, 12, 22)
end
def countdown
Rails.logger.debug 'DEBUG: entering Owner countdown method'
today = Date.today
birthday = Date.new(today.year, birthdate.month, birthdate.day)
if birthday > today
countdown = (birthday - today).to_i
else
countdown = (birthday.next_year - today).to_i
end
end
end
You’ll often need to “get inside” the model or controller to see what’s happen-
ing. The Rails logger is the best tool for the job.
Here are some tricks for the Rails logger.
In a controller, you can use the method logger on its own. In a model, you
have to write Rails.logger (both class and method).
You can use any of the methods logger.debug, logger.info, logger.warn,
logger.error, or logger.fatal to write log messages. By default, you’ll
see any of these messages in the development log. Log messages written with
the logger.debug method will not be recorded in a production log file.
If you want your log messages to stand out, you can add formating code for
color:
For more about the Rails logger, see the RailsGuide: Debugging Rails Appli-
cations.
www.dbooks.org
148 CHAPTER 14. TROUBLESHOOT
Now, with debug statements in the controller and model, we’ll see messages
showing the server’s traverse of the model-view-controller architecture.
Notice how the diagnostic messages in the console window match the headers
in the browser Developer Tools view. The browser’s “Request Method:GET”
matches the server’s “Started GET.” The browser’s “Status Code: 200” matches
the server’s “Completed 200 OK” (you might have to clear the browser’s cache
if the browser is showing “304 Not Modified”).
We can see evidence of the model-view-controller architecture. “Processing by
VisitorsController#new” shows the program flow entering the controller. Our
debug statements show we enter the new method and reveal the value of the
Owner name. The next debug statement reveals the flow has passed to the
Owner model. A diagnostic message shows the controller has rendered the
visitors/new.html.erb view file. Finally, the “Completed 200 OK” message
indicates the response has been sent to the browser.
As we learned, the model-view-controller architecture is an abstract design pat-
tern. We’ve seen it reflected in the file structure of the Rails application direc-
tory. Now we can see it as activity in the server log.
Let’s deliberately create an error condition and see an error page and stack
trace.
Modify the file app/controllers/visitors_controller.rb:
def new
Rails.logger.debug 'DEBUG: entering new method'
@owner = Owner.new
Rails.logger.debug 'DEBUG: Owner name is ' + @owner.name
DISASTER
end
end
To save space, I’m only showing the top line of the stack trace. I’ve eliminated
about sixty lines from the stack trace.
Don’t feel bad if your reaction to a stack trace is an immediate, “TMI!” Indeed,
it is usually Too Much Information. There are times when it pays to carefully
www.dbooks.org
150 CHAPTER 14. TROUBLESHOOT
read through the stack trace line by line, but most often, only the top line of the
stack trace is important.
In this case, both the error page and the top line of the stack trace show the
application failed (I prefer to say, “barfed”) when it encountered an “uninitial-
ized constant” at line 7 of the app/controllers/visitors_controller.rb file in the
new method. It’s easy to find line 7 in the file and see that is exactly where we
added a string that Rails doesn’t understand.
The point of this exercise is to encourage you to read the top line of the stack
trace and use it to diagnose the problem. I’m always surprised how many de-
RAISING AN EXCEPTION 151
Raising an Exception
As you just saw, you can purposefully break your application by adding char-
acters that Rails doesn’t understand. However, there is a better way to force
your program to halt, called raising an exception.
Let’s try it. Modify the file app/controllers/visitors_controller.rb:
def new
Rails.logger.debug 'DEBUG: entering new method'
@owner = Owner.new
Rails.logger.debug 'DEBUG: Owner name is ' + @owner.name
raise 'Deliberate Failure'
end
end
You can throw an error by using the raise keyword from the Ruby API. You
can provide any error message you’d like in quotes following raise.
Here’s the console log after you try to visit the home page:
Before we continue, let’s remove the deliberate failure. Modify the file app/controllers/visit
www.dbooks.org
152 CHAPTER 14. TROUBLESHOOT
def new
Rails.logger.debug 'DEBUG: entering new method'
@owner = Owner.new
Rails.logger.debug 'DEBUG: Owner name is ' + @owner.name
end
end
Rails and the Ruby API provide a rich library of classes and methods to raise
and handle exceptions. For example, you might want to display an error if a
user enters a birthdate that is not in the past. Rails includes various exception
handlers to display errors in production so users will see a helpful web page
explaining the error.
Git
There’s no need to save any of the changes we made for troubleshooting.
You could go to each file and carefully remove the debugging code you added.
But there’s an easier way.
Check which files have changed:
$ git status
# Changes not staged for commit:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: app/controllers/visitors_controller.rb
# modified: app/models/owner.rb
#
no changes added to commit (use "git add" and/or "git commit -a")
The Git command git reset -hard HEAD discards any changes you’ve
made since the most recent commit. Check the status to make sure:
$ git status
# On branch master
nothing to commit, working directory clean
www.dbooks.org
154 CHAPTER 14. TROUBLESHOOT
Chapter 15
155
www.dbooks.org
156 CHAPTER 15. JUST ENOUGH RUBY
to recognize the language keywords and use the correct syntax when you type
Ruby code in your text editor.
To that end, this chapter will review the Ruby keywords and syntax you’ve
already learned. And you’ll extend your knowledge so you’ll be prepared for
the Ruby you’ll encounter in upcoming chapters.
Ruby Example
To improve your reading knowledge of Ruby, we’ll work with an example file
that contains a variety of Ruby expressions.
We won’t use this file in our tutorial application, so you’ll delete it at the end of
this chapter. But we’ll approach it as real Ruby code, so make a file and copy
the code using your text editor.
First we have to consider where the file should go. It will not be a model,
view, controller, or any other standard component of Rails. Rails has a place
for miscellaneous files that don’t fit in the Rails API. We’ll create the file in
the lib/ folder. That’s the folder you’ll use for any supporting Ruby code that
doesn’t fit elsewhere in the Rails framework.
Create a file lib/example.rb:
# This is a comment.
attr_accessor :honorific
attr_accessor :name
attr_accessor :date
def initialize(name,date)
@name = name
@date = date.nil? ? Date.today : date
end
def backwards_name
@name.reverse
end
RUBY EXAMPLE 157
def to_s
@name
end
def titled_name
@honorific ||= 'Esteemed'
titled_name = "#{@honorific} #{@name}"
end
def december_birthdays
born_in_december = [ ]
famous_birthdays.each do |name, date|
if date.month == 12
born_in_december << name
end
end
born_in_december
end
private
def famous_birthdays
birthdays = {
'Ludwig van Beethoven' => Date.new(1770,12,16),
'Dave Brubeck' => Date.new(1920,12,6),
'Buddy Holly' => Date.new(1936,9,7),
'Keith Richards' => Date.new(1943,12,18)
}
end
end
In some ways, this Ruby code is like a poem from Lewis Carroll:
www.dbooks.org
158 CHAPTER 15. JUST ENOUGH RUBY
The code follows the rules of Ruby syntax, and unlike the poem, uses mean-
ingful words. But it is unclear how the author intends anyone to use the code.
If you’re beginning a career as a Rails developer, this won’t be the last time
you look at code and wonder what the author was intending. In this case, I just
want to give you some code that illustrates typical Ruby syntax and structure.
Ruby Keywords
When reading Ruby code, the first challenge is determining which words are
Ruby keywords and which were made up by the developer. Code is only strings
of characters. But some strings have special meaning for everyone and all
others are arbitrary words that only have meaning to an individual developer.
As you gain experience, you’ll recognize Ruby keywords because you’ve seen
them before.
You’ll also recognize a developer’s made-up words because of their position
relative to other words and symbols. Some made-up words will be obvious
because they are just too idiosyncratic to be part of the Ruby language. For
example, you’ll rightly guess that myapp or fluffycat are not part of the
Ruby language.
If you’re reading a Lewis Carroll poem, you could look up words in a dictionary
to see if you find them.
There is only one way to be sure which words are part of the Ruby language:
Check the Ruby API.
As an exercise, pick one of the words from the example code that you think
might be a Ruby keyword and search the API to find it.
If you want to be a diligent student, you can check every keyword in the exam-
ple code to find out whether it is in the Ruby API. It is more practical to learn
to recognize Ruby keywords, which we’ll do next.
RUBY FILES 159
API Documentation
The Ruby API documentation lists every keyword in the language:
Ruby Files
When we write code, we save it in files. We’ve added our miscellaneous exam-
ple file to the lib/ folder.
By convention, Ruby files end with the file extension .rb.
Using IRB
In the “Troubleshooting” chapter, you used IRB (the Interactive Ruby Shell) to
try out Ruby code. You can use IRB to try out the example code in the console.
$ irb
>> load 'lib/example.rb'
=> true
>> require 'date'
=> true
>> ex = Example.new('Daniel',nil)
=> #<Example:0x007fb46c9eecd8 @name="Daniel", @date=#<Date: 2015-12-23 ...
>> list = ex.december_birthdays
=> ["Ludwig van Beethoven", "Dave Brubeck", "Keith Richards"]
>>
Entering the load directive and the filename brings the code into IRB.
The require ’date’ statement loads the Ruby date library.
www.dbooks.org
160 CHAPTER 15. JUST ENOUGH RUBY
Comments
Ruby ignores everything that is marked as a comment. Use comments for notes
to yourself or other programmers.
# This is a comment.
You can also turn code into comments if you don’t want the code to run. This
is a common trick when you want to “turn off” some part of your code but you
don’t want to delete it just yet, because you are trying out alternatives.
THE HEART OF PROGRAMMING 161
• syntax
• conditional execution
• transformation
Computers allow no ambiguity. Code must exactly follow the syntax of a lan-
guage. Typos, guesses, and code that is almost-but-not-quite right will simply
fail, often without any helpful error messages.
Computers seem intelligent because they can execute code conditionally. You
can write a program so that given one set of conditions, certain parts of the
code will execute, and given different conditions, other parts of the code will
execute.
Lastly, programs are written to transform abstractions from one form to another.
That’s why computer programs look like math. When we learn simple arith-
metic, we learn we can take the symbols for numbers and add them together
to make a different number. Computer programs do more than add numbers; a
program can transform words and other abstractions.
Assignment
In Ruby, like many other programming languages, the equals sign indicates we
are assigning a value.
www.dbooks.org
162 CHAPTER 15. JUST ENOUGH RUBY
Object-Oriented Terminology
Software architects use a common vocabulary to talk about programming lan-
guages:
• class
• instance or object
• method
• attribute or property
• inheritance
• class hierarchy
OBJECT-ORIENTED TERMINOLOGY 163
There are three ways to learn what these words mean. You can memorize the
definitions. You can write code and intuitively grasp the meanings. Or you can
gain an understanding by applying metaphors.
Houses
For example, some programming textbooks attempt to explain a class like this:
A blueprint for a house design is like a class definition. All the houses built
from that blueprint are objects of a class we could call House.
Vehicles
Or: The concept of “vehicle” is like a class. Vehicles can have attributes, like
color or number of doors. They have behavior, or methods, like buttons that
turn on lights or honk a horn. The concepts of “truck” or “car” are also classes,
inheriting common characteristics from a superclass “vehicle.” The blue car
in your driveway with four doors is an object, a particular instance of the class
“car.”
Cookies
I like the cookie metaphor the best.
A class definition is like a cookie cutter.
Bits in the computer memory are like cookie dough.
The cookie cutter makes as many individual cookies as you want. Each cookie
is an instance of the Cookie class, with the same shape and size as the others.
Cookies are objects.
You can decorate each cookie with sprinkles, which are attributes that are
unique to each instance. Some cookies get red sprinkles, some get green, but
www.dbooks.org
164 CHAPTER 15. JUST ENOUGH RUBY
Limitations of Metaphors
Definitions
Here are definitions for some of the terms we encounter when we consider
Rails from the perspective of a software architect:
instance or object a unique copy of a class that exists only while a program is
running
attribute or property data that can be set or retrieved from the object
Some of these terms are abstractions that are “made real” in the Ruby API
(such as class and method); others are just terms that describe code, much like
we use terms such as “adjective” or “noun” to talk about the grammar of the
English spoken language.
Classes
You don’t have to create classes to program in Ruby. If you only write simple
programs, you won’t need classes. Classes are used to organize your code and
www.dbooks.org
166 CHAPTER 15. JUST ENOUGH RUBY
make your software more modular. For the software architect, classes make
it possible to create a structure for complex software programs. To use Rails,
you’ll use the classes and methods that are defined in the Rails API.
There is one class at the apex of the Ruby class hierarchy: BasicObject.
BasicObject is a very simple class, with almost no methods of its own. The
Object class inherits from BasicObject. All classes in the Ruby and Rails
APIs inherit behavior from Object. Object provides basic methods such as
nil? and to_s (“to string”) for every class that inherits from Object.
We create a class Example and inherit from Object with the < “inherits from”
operator:
The end statement indicates all the preceding code is part of the Example
class.
In Ruby, all classes inherit from the Object class, so we don’t need to explicitly
subclass from Object as we do here. The example just shows it for teaching
purposes.
Here is the Example class without the explicit subclassing from Object:
class Example
.
.
.
end
Much of the art of programming is knowing what classes are available in the
API and deciding when to subclass to inherit useful methods.
METHODS 167
Methods
Classes give organization and structure to a program. Methods get the work
done.
Any class can have methods. Methods are a series of expressions that return a
result (a value). We say methods describe the class behavior.
A method definition begins with the keyword def and (predictably) ends with
end.
def backwards_name
@name.reverse
end
ex = Example.new('Daniel',nil)
my_backwards_name = ex.backwards_name
=> leinaD
def to_s
@name
end
Here we are overriding the to_s (“to string”) method from the parent Object
class.
Ordinarily, the to_s method returns the object’s class name and an object id.
Here we will return the string assigned to the variable @name.
Most times you won’t override the to_s (“to string”) method. This example
shows how you can override any method inherited from a parent class.
www.dbooks.org
168 CHAPTER 15. JUST ENOUGH RUBY
Dot Operator
The “dot” is the method operator. This tiny punctuation symbol is a powerful
operator in Ruby.
It allows us to call a method to get a result.
Sometimes we say we send a message to the object when we invoke a method,
implying the object will send a result.
Some classes, such as Date, provide class methods which can be called directly
on the class without instantiating it first. For example, you can run this in the
Rails console:
Date.today
=> Tue, 15 Oct 2013
More often, methods are called on variables which are instances of a class. For
example:
We can apply method chaining to objects. For example, String has methods
reverse and upcase (among many others). We could write:
nonsense = 'foobar'
=> "foobar"
reversed = nonsense.reverse
=> "raboof"
capitalized = reversed.upcase
=> "RABOOF"
'foobar'.reverse.upcase
=> "RABOOF"
Classes create a structure for our software programs and methods do all the
work.
You’ll see question marks and exclamation points (sometimes called the “bang”
character) used in method names. These characters are simply a naming con-
vention for Ruby methods.
The question mark indicates the method will return a boolean value (true or
false).
The bang character indicates the method is “dangerous.” In some cases it means
the method will change the object rather just return a result. In Rails an excla-
mation point often means the method will throw an exception on failure rather
than failing silently.
Initialize Method
Objects are created from classes before they are used. As I suggested earlier,
class definitions are cookie cutters; the Ruby interpreter uses them to cut cook-
ies. When we call the new method, we press the cookie cutter into the dough
and get a new object. All the cookies will have the same shape but they can be
decorated differently, by sprinkling attributes of different values.
The initialize method is one of the ways we sprinkle attributes on our
cookie.
www.dbooks.org
170 CHAPTER 15. JUST ENOUGH RUBY
def initialize(name,date)
Method Parameters
Methods are useful when they operate on data.
If we want to send data to a method, we define the method and indicate it will
accept parameters. Parameters are placeholders for data values. The values
that are passed to a method are arguments. “Parameters” are empty place-
holders and “arguments” are the actual values. In practice, “parameters” and
“arguments” are terms that are used interchangeably and not many developers
will notice if you mix up the terms.
Our initialize method takes name and date arguments:
def initialize(name,date)
Ruby is clever with method parameters. You can define a method and specify
default values for parameters. You can also pass extra arguments to a method
if you define a method that allows optional parameters. This makes methods
very flexible.
We separate our parameters with commas. For readability, we enclose our list
of parameters in parentheses. In Ruby, parentheses are always optional but they
often improve readability.
VARIABLE 171
Variable
In Ruby, everything is an object. We can assign any object to a variable. The
variable works like an alias. We can use a variable anywhere as if it were the
assigned object. The variable can be assigned a string, a numeric value, or an
instance of any class (all are objects).
name
You can assign a new value to a variable anywhere in your method. You can
assign a different kind of object if you want. You can take away someone’s
name and give them a number. We can create a variable player, assign it the
string ’Jackie Robinson’, replace the value with an integer 42, or even a
date such as Date.new(1947,4,15).
Symbol
Obviously, we see many symbols when we read Ruby code, such as punctua-
tion marks and alphanumeric characters. But symbol has a specific meaning in
Ruby. It is like a variable, but it can only be assigned a value once. After the
initial assignment, it is immutable; it cannot be changed.
You will recognize a symbol by the colon that is always the first character.
:name
Symbols are efficient and fast because the Ruby interpreter doesn’t have to
work to check their current values.
You’ll often see symbols used in Rails where you might expect a variable.
www.dbooks.org
172 CHAPTER 15. JUST ENOUGH RUBY
Attributes
In an object, methods do the work and data is stored as variables. We can use
the initialize method to input data to the object. We can’t access data in
variables from outside the object unless it is exposed as attributes.
Classes can have attributes, which we can “set” and “get.” That is, we can es-
tablish a value for an attribute and retrieve the value by specifying the attribute
name.
Attributes are a convenient way to push data to an object and pull it out later.
In Ruby, attributes are also called properties.
Here we use the attr_accessor directive to specify that we want to expose
honorific, name and date attributes.
attr_accessor :honorific
attr_accessor :name
attr_accessor :date
ex = Example.new('Daniel',nil)
my_name = ex.name
In Ruby, attributes are just specialized methods that expose data outside the
object.
Instance Variable
Inside an object, an ordinary variable only can be used within the method in
which it appears. If you use a variable with the same name in two different
INSTANCE VARIABLE 173
methods, it will have a different value in each method. The scope of a variable
is limited to the method in which it is used.
Often you want a variable to be available throughout an instance, within any
method. You can declare an instance variable by using an @ (at) sign as the
first character of the variable name.
The instance variable can be used by any method after the class is instantiated.
@name = name
The values assigned to instance variables are unique for every instance of the
class. If you create multiple instances of a class, each will have its own values
for its instance variables. Here we create two instances of the Example class.
The @name instance variable will be “Daniel” in the first instance and “Foobar”
in the second instance.
ex1 = Example.new('Daniel',nil)
ex2 = Example.new('Foobar',nil)
An instance variable is not visible outside the object in which it appears; but
when you create an attr_accessor, it creates an instance variable and makes
it accessible outside the object.
www.dbooks.org
174 CHAPTER 15. JUST ENOUGH RUBY
learn that the variable with the @ (at) sign is called an instance variable and is
only available within the scope of the instance (practically speaking, to other
methods in the class definition). That leads to a question: Why is an instance
variable available inside a view?
There is a good reason. A Rails view is NOT a separate class. It is a tem-
plate and, under the hood, it is part of the current controller object. From the
viewpoint of a programmer, a Rails controller and a view are separate files,
segregated in separate folders. From the viewpoint of a software architect, the
controller is a single object that evaluates the template code, so an instance
variable can be used in the view file.
This example shows us that the programmer and the software architect have
different perspectives on a Rails application. Understanding Rails requires an
integration of multiple points of view.
if not x
x = y
end
Conditional
Conditional logic is fundamental to programming. Our code is always a path
with many branches.
When the Ruby interpreter encounters an if keyword, it expects to find an
expression which evaluates as true or false (a boolean).
If the expression is true, the statements following the condition are executed.
If the expression is false, any statements are ignored, unless there is an else,
in which case an alternative is executed.
if date.month == 12
.
.
.
end
www.dbooks.org
176 CHAPTER 15. JUST ENOUGH RUBY
Ternary Operator
A basic conditional structure might look like this:
if date.nil?
@date = Date.today
else
@date = date
end
We test if date is undefined (nil). If nil, we assign today’s date to the instance
variable @date. If date is already assigned a value, we assign it to the instance
variable @date. This is useful in the initialize(name,date) method in
our example code because we want to set today’s date as the default value for
the instance variable @date if the parameter date is nil.
Ruby developers like to keep their code tight and compact. So you’ll see a con-
densed version of this conditional structure often, particularly when a default
value must be assigned.
This compact conditional syntax is named the ternary operator because it has
three components. Here is the syntax:
This is another example of Ruby syntax that you must learn to recognize by
sight because it is difficult to interpret if you have never seen it before.
For more Ruby code that has been condensed into obscurity, see an article on
Ruby Golf. Ruby golf is the sport of writing code that uses as few characters
as possible.
INTERPOLATION 177
Interpolation
Rubyists love to find special uses for orthography such as hashmarks and curly
braces. It seems Rubyists feel sorry for punctuation marks that don’t get much
use in the English language and like to give them new jobs.
We already know that we can assign a string to a variable:
@honorific = 'Mr.'
@name = 'Foobar Kadigan'
titled_name = @honorific + ' ' + @name
=> "Mr. Foobar Kadigan"
Single quote marks indicate a string. In the example above, we enclose a space
character within quote marks so we add a space to our string.
You can eliminate the ungainly mix of plus signs, single quote marks, and space
characters in the example above.
Use double quote marks and you can perform interpolation, which gives a new
job to the hashmark and curly brace characters:
@honorific = 'Mr.'
@name = 'Foobar Kadigan'
titled_name = "#{@honorific} #{@name}"
=> "Mr. Foobar Kadigan"
The hashmark indicates any expression within the curly braces is to be evalu-
ated and returned as a string. This only works when you surround the expres-
sion with double quote marks.
www.dbooks.org
178 CHAPTER 15. JUST ENOUGH RUBY
Interpolation is cryptic when you first encounter the syntax, but it streamlines
string concatenation.
Access Control
Any method you define will return a result.
Sometimes you want to create a method that only can be used by other methods
in the same class. This is common when you need a simple utility method that
is used by several other methods.
Any methods that follow the keyword private should only be used by meth-
ods in the same class (or a subclass).
private
You often see private methods in Rails. Ruby provides a protected keyword as
well, but the difference between protected and private is subtle and protected
is seldom seen in Rails applications.
Hash
Our example code includes a private method named famous_birthdays that
returns a collection of names and birthdays of famous musicians.
Computers have always been calculation machines; they are just as important
in managing collections.
One important type of collection is named a Hash. A Hash is a data structure
that associates a key to some value. You retrieve the value based upon its key.
This construct is called a dictionary, an associative array, or a map in other
languages. You use the key to “look up” a value, as you would look up a
definition for a word in a dictionary.
HASH 179
You’ll recognize a Hash when you see curly braces (again, Rubyists give a job
to under-utilized punctuation marks).
birthdays = {
'Ludwig van Beethoven' => Date.new(1770,12,16),
'Dave Brubeck' => Date.new(1920,12,6),
'Buddy Holly' => Date.new(1936,9,7),
'Keith Richards' => Date.new(1943,12,18)
}
Rubyists also like to create novel uses for mathematical symbols. The com-
bination of an = (equals) sign and > (greater than) sign is called a hashrocket.
The => (hashrocket) operator associates a key and value pair in a Hash. You’ll
often see hashrockets in code written before Ruby 1.9. Ruby 1.9 introduced a
new syntax using colons instead of hashrockets.
Whether with colons or hashrockets, you’ll often see Hashes used in Rails.
With Ruby 1.9 and later, here’s how we associate key and value pairs in a Hash:
birthdays = {
beethoven: Date.new(1770,12,16),
brubeck: Date.new(1920,12,6),
holly: Date.new(1936,9,7),
richards: Date.new(1943,12,18)
}
Here, instead of using a string as the key, we are using Ruby symbols, which
enable faster processing. The : (colon) character associates the key and value.
Ordinarily, a symbol is defined with a leading colon character. In a Hash, a
trailing colon makes a string into a symbol.
If you want to transform a string containing spaces into a symbol in a Hash,
you can do it, though the syntax is awkward:
www.dbooks.org
180 CHAPTER 15. JUST ENOUGH RUBY
birthdays = {
'Ludwig van Beethoven': Date.new(1770,12,16)
}
Array
An Array is a list. Arrays can hold objects of any data type. In fact, arrays can
contain a mix of different objects. For example, an array can contain a string
and another array (this is an example of a nested array).
An array can be instantiated with square brackets:
born_in_december = [ ]
If we don’t want to use quote marks and commas to separate strings in a list,
we can use the %w syntax:
my_list = Array.new
=> []
my_list.push 'apples'
=> ["apples"]
my_list.push 'oranges'
=> ["apples", "oranges"]
ITERATOR 181
In our example code, we use the << shovel operator to add items to the array:
Iterator
Of all the methods available for a Ruby collection such as Hash or Array, the
iterator may be the most useful.
You’ll recognize an iterator when you see the each method applied to a Hash
or Array:
famous_birthdays.each
The each keyword is always followed by a block of code. Each item in an Ar-
ray, or key-value pair in a Hash, is passed to the block of code to be processed.
Block
You can recognize a block in Ruby when you see a do ... end structure. A
block is a common way to process each item when an iterator such as each is
applied to a Hash or Array.
In our example, we iterate over the famous_birthdays hash:
www.dbooks.org
182 CHAPTER 15. JUST ENOUGH RUBY
Within the two pipes (or bars), we assign the key and value to two variables.
The block is like an unnamed method. The two variables are available only
within the block. As each key-value pair is presented by the iterator, the vari-
ables are assigned, and the statements in the block are executed.
In our example code, we evaluate each date in the famous_birthdays hash
to determine if the musician was born in December. When we find a December
birthday, we add the name of the musician to the born_in_december array:
When you use a block within a method, any variable in your method is available
within the block. That’s why we can add name to the array born_in_december.
Computer scientists consider a block to be a programming language construct
called a closure. Ruby has other closures, including the proc (short for proce-
dure) and the lambda. Though blocks are common you’ll seldom see procs or
lambdas in ordinary Rails code. They are more common in the Rails source
code where advanced programming techniques are used more frequently.
The key point to know about a block (or a proc or a lambda) is that it works
like a method. Though you don’t see a method definition, you can use a block
to evaluate a sequence of statements and obtain a result.
RAILS AND MORE KEYWORDS 183
We’ve looked at only a few of the keywords and constructs you will see in Ruby
code. The exercise has improved your Ruby literacy, so you’ll have an easier
time reading Ruby code.
Nothing in the exercise is Rails. The example code only uses keywords from
the Ruby API.
Rails has its own API, with hundreds of classes and methods. The Rails API
uses the syntax and keywords of the Ruby language to construct new classes
and create new keywords that are specific to Rails and useful for building web
applications.
We say Ruby is a general-purpose language because it can be used for any-
thing. Rails is a domain-specific language (DSL) because it is used only by
people building web applications (in this sense, “domain” means area or field
of activity). Ruby is a great language to use for building a DSL, which is why
it was used for Rails. Unlike some other programming languages, Ruby eas-
ily can be extended or tweaked. For example, developers can redefine classes,
add extra methods to existing classes, and use the special method_missing
method to handle method calls that aren’t previously defined. Software archi-
tects call this metaprogramming which simply means clever programming that
twists and reworks the programming language.
When you add a gem to a Rails project, you’ll add additional keywords. Some
of the most powerful gems add their own DSLs to your project. For example,
the Cucumber gem provides a DSL for turning user stories into automated tests.
Adding Rails, additional gems, and DSLs provides powerful functionality at
the cost of complexity. But it all conforms to the syntax of the Ruby language.
As you learn to recognize Ruby keywords and language structures, you’ll be
able to pick apart the complexity and make sense of any code.
www.dbooks.org
184 CHAPTER 15. JUST ENOUGH RUBY
More Ruby
To develop your proficiency as a Rails developer, I hope you will make an
effort to learn Ruby as you learn Rails. Don’t be lazy; when you encounter a
bit of Ruby you don’t understand, make an effort to find out what is going on.
Spend time with a Ruby textbook or interactive course when you work on Rails
projects.
Collaborative Learning
The best way to learn Ruby is to actually use it. That’s the concept behind this
site:
• Exercism.io
With Exercism, you’ll work though code exercises and get feedback from other
learners.
Online Tutorials
• TryRuby.org - free browser-based interactive tutorial from Code School
• Codecademy Ruby Track - free browser-based interactive tutorials from
Codecademy
• Ruby Koans - free browser-based interactive exercises from Jim Weirich
and Joe O’Brien
• Ruby in 100 Minutes - free tutorial from JumpstartLab
• Code Like This - free tutorials by Alex Chaffee
• RailsBridge Ruby - basic introduction to Ruby
GIT 185
Books
• Learn To Program - free ebook by Chris Pine
• Learn Code the Hard Way - free from Zed Shaw and Rob Sobers
Newsletters
• Practicing Ruby - $8/month for access to over 90 helpful articles on Ruby
Screencasts
• RubyTapas - $9/month for access to over 100 screencasts on Ruby
Git
There’s no need to save the file lib/example.rb file we created to learn Ruby.
www.dbooks.org
186 CHAPTER 15. JUST ENOUGH RUBY
$ rm lib/example.rb
$ git status
# On branch master
nothing to commit, working directory clean
Template Languages
HTML is intended for markup, which means applying formatting to a text file.
For a web application, ordinary HTML is not sufficient; we need to mix in
Ruby code. We’ll use a templating language that gives us a syntax for mixing
HTML tags and Ruby code. The Ruby code will be processed by a templating
engine built into Rails. The output will be pure HTML sent to the browser.
The most popular templating language available for Rails is ERB, Embedded
Ruby, which is the Rails default.
187
www.dbooks.org
188 CHAPTER 16. LAYOUT AND VIEWS
In the “Concepts” chapter in Book One, you learned that components of Rails
can be mixed for different “stacks.” Some developers substitute Haml or Slim
for ERB. We’ll use ERB in this book because it is the most popular.
<h3>Home</h3>
<p>Welcome to the home of <%= @owner.name %>.</p>
<p>I was born on <%= @owner.birthdate %>.</p>
<p>Only <%= @owner.countdown %> days until my birthday!</p>
The first line in the file contains an HTML heading tag, <h3>, with headline
text, “Home.”
When you used the browser Developer Tools view to see the HTML file re-
ceived by the server, you saw this:
<!DOCTYPE html>
<html>
<head>
<title>LearnRails</title>
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="..." />
<link rel="stylesheet" media="all" href="/assets/application.css?body=1" data-turbolinks-track="
<script src="/assets/jquery.js?body=1" data-turbolinks-track="reload"></script>
<script src="/assets/jquery_ujs.js?body=1" data-turbolinks-track="reload"></script>
<script src="/assets/turbolinks.js?body=1" data-turbolinks-track="reload"></script>
<script src="/assets/action_cable.js?body=1" data-turbolinks-track="reload"></script>
<script src="/assets/cable.js?body=1" data-turbolinks-track="reload"></script>
<script src="/assets/application.js?body=1" data-turbolinks-track="reload"></script>
</head>
<body>
<h3>Home</h3>
<p>Welcome to the home of Foobar Kadigan.</p>
<p>I was born on 1990-09-22.</p>
WHERE DID ALL THE EXTRA HTML COME FROM? 189
</body>
</html>
If you’ve built websites before, you’ll recognize the HTML file conforms to
the HTML5 specification, with a DOCTYPE, <head> and <body> tags, and
miscellaneous tags in the HEAD section, including a title and various CSS and
JavaScript assets.
If you look closely, you’ll see some HTML attributes you might not recognize,
for example the data-turbolinks-track attribute. That is added by Rails
to support turbolinks, for faster loading of webpages.
For the most part, everything is ordinary HTML. But only part of it originates
from the view file we’ve created for our home page.
We say Rails “renders” (or “delivers”) a new view by combining two files.
Let’s examine the application layout file.
Open the file app/views/layouts/application.html.erb:
www.dbooks.org
190 CHAPTER 16. LAYOUT AND VIEWS
<!DOCTYPE html>
<html>
<head>
<title>LearnRails</title>
<%= csrf_meta_tags %>
<body>
<%= yield %>
</body>
</html>
Static pages delivered from the public folder do not use the default application
layout. But every page generated by the model-view-controller architecture in
the app/ folder incorporates the default application layout, unless you specify
otherwise.
The default application layout is where you put HTML that you want to include
on every page of your website.
Remember when we looked at the hidden code in the controller that renders a
view? The controller uses the render method to combine the view file with
the application layout.
Here’s the Visitors controller, again, with the hidden render method revealed:
def new
@owner = Owner.new
render 'visitors/new'
end
end
Alternatively, you could tell the controller to render the view without any ap-
plication layout:
Yield
How does the render method insert the view file in the application layout?
How do the two files get combined?
Notice that the default application layout contains the Ruby keyword yield.
.
.
.
<%= yield %>
.
.
.
The yield keyword is replaced with a view file that is specific to the controller
and action, in this case, the app/views/visitors/new.html.erb view file.
The content from the view is inserted where you place the yield keyword.
The yield keyword pulls in another view file.
www.dbooks.org
192 CHAPTER 16. LAYOUT AND VIEWS
Yield Variations
We won’t do it, but you could also use the yield keyword to insert a sidebar
or a footer.
Rails provides ways to insert content into a layout file at different places. The
content_for method is helpful when your layout contains distinct regions
such as sidebars and footers that should contain their own blocks of content.
For example, you could create an application layout that includes a sidebar.
This is just an example, so don’t add it to the application you are building:
<!DOCTYPE html>
<html>
<head>
<title>LearnRails</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application',
'data-turbolinks-track': 'reload' %>
</head>
<body>
<div class="main">
<%= yield %>
</div>
<div class="sidebar">
<%= yield :sidebar %>
</div>
</body>
</html>
This view file provides both the main content and a sidebar:
This section gets inserted at the <%= yield :sidebar %> location:
ERB DELIMITERS 193
The rest of the file gets inserted at the main <%= yield %> location.
Again, don’t add this to your application. I’m just offering it as an example of
multiple yield statements.
The reference RailsGuides: Layouts and Rendering in Rails explains more
about using yield and content_for.
ERB Delimiters
Earlier, we saw ERB <%= ... %> delimiters allow us to insert Ruby ex-
pressions which are replaced by the result of evaluating the code. Here is an
example that displays the number 4
<%= 2 + 2 %>
Look closely and you’ll see this ERB delimiter is slightly different:
An ERB delimiter that does not contain the = (equals) sign will execute Ruby
code but will not display the result. It is commonly used to add Ruby blocks to
HTML code, so you’ll often see do and end statements within ERB <% ...
%> delimiters. The example above will create three list items, like this:
www.dbooks.org
194 CHAPTER 16. LAYOUT AND VIEWS
<li>list item</li>
<li>list item</li>
<li>list item</li>
It is only used for adding comments. The expression within the ERB <%# ...
%> delimiters will not execute and will not appear when the page is output as
HTML.
Why do we need this cryptic code? It turns out that almost any website that
accepts user input via a form is vulnerable to a security bug (an exploit) named
a cross-site request forgery. To prevent rampant CSRF exploits, the Rails core
team includes the csrf_meta_tags view helper in the default application
layout. Rails provides a number of similar features that make websites more
secure.
A Rails view file becomes much less mysterious when you realize that many of
the keywords you see are view helpers. Strange new keywords may be part of
the Rails API. Or they may be provided by gems you’ve added (gem developers
often use the Ruby DSL capability to create new keywords). Think of it this
way: Ruby gives developers the power to create an unlimited number of new
“HTML tags.” These tags are not really HTML because they are not part of the
HTML specification. But they serve as shortcuts to produce complex snippets
of HTML and content.
Now that we’ve learned about view helpers, we can start building our default
application layout.
www.dbooks.org
196 CHAPTER 16. LAYOUT AND VIEWS
gem 'rails_layout'
The -force argument will force the gem to replace the existing app/views/layouts/applicat
file.
If you have the app/views/layouts/application.html.erb file open in your text
editor, it will change.
BASIC BOILERPLATE 197
• app/assets/stylesheets/application.css
to:
• app/assets/stylesheets/application.css.scss
• app/views/layouts/application.html.erb
• app/assets/stylesheets/simple.css
• app/views/layouts/_messages.html.erb
• app/views/layouts/_navigation.html.erb
• app/views/layouts/_navigation_links.html.erb
Examining these files closely will reveal a great deal about the power of Rails.
We’ll dedicate the rest of this chapter to exploring the contents of these files.
Basic Boilerplate
Open the file app/views/layouts/application.html.erb:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= content_for?(:title) ? yield(:title) : "Learn Rails" %></title>
<meta name="description" content=
www.dbooks.org
198 CHAPTER 16. LAYOUT AND VIEWS
The rest of the file may be unfamiliar. We’ll examine it line by line.
Adding Boilerplate
Webmasters who build static websites are accustomed to setting up web pages
with “boilerplate,” or basic templates for a standard web page. The well-known
HTML5 Boilerplate project has been recommending “best practice” tweaks to
web pages since 2010. Very few of the HTML5 Boilerplate recommendations
are relevant for Rails developers, as Rails already provides almost everything
ADDING BOILERPLATE 199
required. We’ll discuss one important boilerplate item and a few “nice to have”
extras.
If you want to learn more, the article HTML5 Boilerplate for Rails Developers
looks at the recommendations.
Viewport
If you want to maximize traffic to your website, you should make your web
pages search-engine friendly. That means adding title and description metatags.
Google uses contents of the title tag to display titles in search results. And it
will sometimes use the content of a description metatag in search results snip-
pets. See Google’s explanation of how it uses Site Title and Description. Good
titles and descriptions improve clickthrough from Google searches.
Title and description looks like this:
www.dbooks.org
200 CHAPTER 16. LAYOUT AND VIEWS
The rails_layout gem has created a default title and description based on our
project name.
Later in the tutorial, we’ll see how to use a content_for statement to set a
title and description for each individual page.
The code is complex if you haven’t seen advanced Ruby before. It uses the
Ruby ternary operator which maximizes compactness at the price of intro-
ducing obscurity. You’ll recall from the “Just Enough Ruby” chapter that it
is a fancy conditional statement that says, “if content_for?(:title) is
present in the view file, use yield(:title) to include it, otherwise just dis-
play ‘Learn Rails’.”
Asset Pipeline
You may have noticed these Rails helper methods:
• stylesheet_link_tag
• javascript_include_tag
These are tags that add CSS and JavaScript to the web page using the Rails
asset pipeline.
The Rails asset pipeline utility is one of the most powerful features of the plat-
form. It offers convenience to the developer and helps organize an applica-
tion; more importantly, it improves the speed and responsiveness of any com-
plex website. If you’re going to do any front-end development with CSS or
JavaScript in Rails, you must understand the Rails asset pipeline. Here’s how
it works.
ASSET PIPELINE 201
<!DOCTYPE html>
<html>
<head>
<title>Page that uses multiple JavaScript files</title>
<script src="jquery.js" type="text/javascript"></script>
<script src="jquery.plugin.js" type="text/javascript"></script>
<script src="custom.js" type="text/javascript"></script>
</head>
The same is true for CSS files in non-Rails websites. You add a <link> tag
for each stylesheet file. With multiple stylesheets, the HEAD section of your
application layout might look like this:
<!DOCTYPE html>
<html>
<head>
<title>Page that uses multiple CSS files</title>
<link href="core.css" rel="stylesheet" type="text/css" />
<link href="site.css" rel="stylesheet" type="text/css" />
<link href="custom.css" rel="stylesheet" type="text/css" />
</head>
If you want to handle CSS and JavaScript without Rails, you can place your
files in the public folder. If you do so, every time you add a JavaScript or CSS
file, you must modify the application layout file. Instead, use the asset pipeline
and simplify this.
www.dbooks.org
202 CHAPTER 16. LAYOUT AND VIEWS
• app/assets/javascripts/
• app/assets/stylesheets/
Any JavaScript and CSS file you add to these folders is automatically added to
every page.
In development, when the web browser makes a page request, the files in the
asset pipeline folders are combined together and concatenated as single large
files, one for JavaScript and one for CSS.
If you examine the application layout file, you’ll see the tags that perform this
service:
Using the asset pipeline, there is no need to modify the application layout file
each time you create a new JavaScript or CSS file. Create as many files as you
need to organize your JavaScript or CSS code and, in production, you’ll auto-
matically get one single file delivered to the browser. In development mode,
Rails continues to deliver multiple files for easier debugging.
In production, there’s a big performance advantage with the asset pipeline. Re-
questing files from the server is a time-consuming operation for a web browser,
so every extra file request slows down the browser. The Rails asset pipeline
eliminates the performance penalty of multiple <script> or <link> tags.
The Rails asset pipeline also compresses JavaScript and CSS files for faster
page loads.
NAVIGATION LINKS 203
Navigation Links
Every website needs navigation links.
You can add navigation links directly to your application layout but many Rails
developers prefer to create a partial template —-a “partial”—-to better organize
the default application layout.
Introducing Partials
A partial is similar to any view file, except the filename begins with an under-
score character. Place the file in any view folder and you can use the render
keyword to insert the partial.
We’re not going to add a footer to our tutorial application, but here is how we
could do it. We’d use the render keyword with a file named app/views/layouts/_footer.htm
Notice that you specify the folder within the app/views/ directory with a trun-
www.dbooks.org
204 CHAPTER 16. LAYOUT AND VIEWS
cated version of the filename. The render method doesn’t want the _ under-
score character or the .html.erb file extension. That can be confusing; it
makes sense when you remember that Rails likes “convention over configura-
tion” and economizes on extra characters when possible.
We’re not going to add a footer to our application, but we will add navigation
links by using a partial. First, let’s learn about link helpers.
<ul class="nav">
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
Rails gives us another option, however. We can use the Rails link_to view
helper instead of the HTML <a> anchor tag. The Rails link_to helper elim-
inates the crufty <> angle brackets and the unnecessary href="". More im-
portantly, it adds a layer of abstraction, using the routing configuration file to
form links. This is advantageous if we make changes to the location of the
link destinations. Earlier, when we created a static “About” page, we first
set the config/routes.rb file with a route to the “About” page: root to:
redirect(’/about.html’). Later we removed the static “About” page and
set the config/routes.rb file with a route to the dynamic home page: root to:
’visitors#new’. If we used the raw HTML <a> anchor tag, we’d have to
change the raw HTML everywhere we had a link to the home page. Using the
Rails link_to helper, we name a route and make any changes once, in the
config/routes.rb file.
When you use the Rails link_to helper, you’ll avoid the problem of link main-
tenance that webmasters face on static websites. Some webmasters like to use
NAVIGATION LINKS 205
absolute URLs, specifying a host name in the link, for example http://www.example.co
Absolute URLs are a headache when moving the site, for example from staging.example
to www.example.com. The problem is avoided by using relative URLs, such
as /about.html, about.html, or even ../about.html. But relative URLs
are fragile, and moving files or directories often results in overlooked and bro-
ken links. Instead, with the Rails link_to helper, you always get the destina-
tion location specified in the config/routes.rb file.
Navigation Partial
.
.
.
<%= render 'layouts/navigation' %>
.
.
.
<ul class="nav">
<li><%= link_to 'Home', root_path %></li>
<%= render 'layouts/navigation_links' %>
</ul>
www.dbooks.org
206 CHAPTER 16. LAYOUT AND VIEWS
The navigation partial includes another partial, which we’ll call the navigation
links partial:
.
.
.
<%= render 'layouts/navigation_links' %>
.
.
.
This demonstrates that one partial can include another partial, so that partials
can be “nested.”
Flash Messages
Rails provides a standard convention to display alerts (including error mes-
sages) and other notices (including success messages), called a flash message.
FLASH MESSAGES 207
The name comes from the term “flash memory” and should not be confused
with the “Adobe Flash” web development platform that was once popular for
animated websites. The flash message is documented in the RailsGuides: Ac-
tion Controller Overview.
Here’s a flash message you might see after logging in to an application:
def new
@owner = Owner.new
flash[:notice] = 'Welcome!'
flash[:alert] = 'My birthday is soon.'
end
end
If you test the application after adding the messages to the VisitorsController,
you’ll see two flash messages appear on the page.
www.dbooks.org
208 CHAPTER 16. LAYOUT AND VIEWS
Rails provides the flash object so that messages can be created in the con-
troller and displayed on the rendered web page.
In this example, we create a flash message by associating the object flash[:notice]
with the string ’Welcome!’. We can assign other messages, such as flash[:alert]
or even flash[:warning]. In practice, Rails uses only :notice and :alert
as flash message keys so it is wise to stick with just these.
def new
@owner = Owner.new
flash.now[:notice] = 'Welcome!'
flash.now[:alert] = 'My birthday is soon.'
end
end
Using flash.now will make sure the message only appears on the rendered
FLASH MESSAGES 209
page and will not persist after a user follows a link to a new page.
If you ever see a “sticky” flash message that won’t go away, you need to use
flash.now instead of flash.
In this simple example, we use each to iterate through the flash hash, retrieving
www.dbooks.org
210 CHAPTER 16. LAYOUT AND VIEWS
a key and value that are passed to a block to be output as a string. We’ve
chosen the variable names key and value but the names are arbitrary. In the
next example, we’ll use name and msg as variables for the key-value pair. The
output string will appear as HTML like this:
<div class="notice">Welcome!</div>
<div class="alert">My birthday is soon.</div>
It improves on our simple Ruby example in several ways. First, the expression
if msg.is_a?(String) serves as a test to make sure we only display mes-
sages that are strings. Second, we use the Rails content_tag view helper to
create the HTML div. The content_tag helper eliminates the messy soup
of angle brackets and quote marks we used to create the HTML output in the
example above. Finally, we apply a CSS class and combine the word “flash”
with “notice” or “alert” to make the CSS class.
We include the flash messages partial in our application layout with the expres-
sion:
HTML5 ELEMENTS 211
.
.
.
<%= render 'layouts/messages' %>
.
.
.
HTML5 Elements
Let’s look again at the app/views/layouts/application.html.erb file.
To complete our examination of the application layout file, we’ll look at a few
structural elements. These elements are not unique to a Rails application and
will be familiar to anyone who has done front-end development.
Notice the tags that are structural elements in the HTML5 specification:
• <header>
• <main>
These elements add structure to a web page. The tags don’t add any new be-
havior but make it easier to determine the structure of the page and apply CSS
styles.
We wrap the navigation partial in the <header> tag:
<header>
<%= render 'layouts/navigation' %>
</header>
www.dbooks.org
212 CHAPTER 16. LAYOUT AND VIEWS
<main role="main">
<%= render 'layouts/messages' %>
<%= yield %>
</main>
Application Layout
Our application layout is complete. We don’t have to add anything because the
rails_layout gem has created everything we need.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
SIMPLE CSS 213
Simple CSS
So far, we’ve examined four files that were added by the rails_layout gem:
• app/views/layouts/application.html.erb
• app/views/layouts/_messages.html.erb
• app/views/layouts/_navigation.html.erb
• app/views/layouts/_navigation_links.html.erb
www.dbooks.org
214 CHAPTER 16. LAYOUT AND VIEWS
Let’s examine the CSS file that was created by the rails_layout gem.
Open the file app/assets/stylesheets/simple.css:
/*
* Simple CSS stylesheet for a navigation bar and flash messages.
*/
main {
background-color: #eee;
padding-bottom: 80px;
width: 100%;
}
header {
border: 1px solid #d4d4d4;
background-image: linear-gradient(to bottom, white, #f2f2f2);
background-color: #f9f9f9;
-webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
ul.nav li {
display: inline;
}
ul.nav li a {
padding: 10px 15px 10px;
color: #777777;
text-decoration: none;
text-shadow: 0 1px 0 white;
}
.flash_notice, .flash_alert {
padding: 8px 35px 8px 14px;
margin-bottom: 20px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
border: 1px solid #fbeed5;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 20px;
}
.flash_notice {
background-color: #dff0d8;
border-color: #d6e9c6;
color: #468847;
}
.flash_alert {
background-color: #f2dede;
border-color: #eed3d7;
TEST THE APPLICATION 215
color: #b94a48;
}
If you already know CSS, you’ll see we’ve set a background color for the main
section of the page. We’ve also set styles for a header, navigation links, and
flash messages. This book is about Rails, not CSS, so we won’t examine this
closely. For more on CSS, there are thousands of tutorials on the web, but I
like these:
• Codeacademy
• HTML Dog
Remember what we learned about the Rails asset pipeline. By default, any
CSS file in the app/assets/stylesheets/ folder will be added automatically to
the application.css file that is included in the default application layout.
In the next chapter, we remove the app/assets/stylesheets/simple.css and use
Bootstrap to supply styles for the header, navigation links, and flash messages.
For now, the simple.css file adds some basic styling and layout to the applica-
tion.
$ rails server
www.dbooks.org
216 CHAPTER 16. LAYOUT AND VIEWS
If you experimented with adding flash messages “Welcome” and “My birthday
is soon,” you’ll see the messages when you visit the home page.
Our home page now has only one navigation link, for “Home.” We’ll add links
for “About” and “Contact” pages soon.
Git
Let’s commit our changes to the Git repository and push to GitHub:
$ git add -A
$ git commit -m "update application layout"
$ git push
Chapter 17
Front-End Framework
This chapter discusses front-end development and design using CSS. I’ll show
you how to add style to a Rails application, using Bootstrap for a simple theme.
What do we mean by “front-end development”? A website back end is the Rails
application that assembles files that are sent to the browser, plus a database and
any other server-side services. A website front end is all the code that runs
in the browser. Everything that controls the appearance of the website in the
browser is the responsibility of a front-end developer, including page layout,
CSS stylesheets, and JavaScript code.
Front-end development has grown increasingly important as websites have be-
come more sophisticated. And front-end technology has grown increasingly
complex, to the degree that front-end development has become a job for spe-
cialists.
Front-end developers are primarily concerned with:
217
www.dbooks.org
218 CHAPTER 17. FRONT-END FRAMEWORK
For years, front-end development was haphazard; webmasters each had their
own quirky techniques. Around the time that Rails became popular, front-end
developers at large companies began to share best practices and establish open
source projects to bring structure and consistency to front-end development,
leading to development of CSS frameworks.
CSS Frameworks
Web developers began putting together “boilerplate” CSS stylesheets as early
as 2000, when browsers first began to fully support CSS. Boilerplate CSS made
it easy to reuse CSS stylesheet rules from project to project. More importantly,
designers often implemented “CSS reset” stylesheets to enforce typographic
uniformity across different browsers.
Engineers at Yahoo! released the Yahoo! User Interface Library (YUI) as an
open source project in February 2006. Inspired by an article by Jeff Croft,
and reacting to the huge size of the YUI library, independent developers began
releasing other CSS frameworks such as the 960 grid system and the Blueprint
CSS framework.
There are dozens of CSS frameworks. In general, they all seek to implement a
common set of requirements:
• A typographic baseline
• CSS reset for default browser styles
• A stylesheet for printing
More recently, with the ubiquity of smartphones and tablets, CSS frameworks
support responsive web design, accommodating differences in screen sizes
across a range of devices.
In tandem with the development of CSS frameworks, we’ve seen the emergence
of JavaScript libraries and frameworks.
www.dbooks.org
220 CHAPTER 17. FRONT-END FRAMEWORK
Front-End Frameworks
Front-end frameworks combine CSS and JavaScript libraries. Many elements
that are found on sophisticated web pages, such as modal windows or tabs,
CSS PREPROCESSING WITH SASS 221
• Bootstrap
• Zurb Foundation
• Bourbon Neat
• Semantic UI
Each has its fans, though Bootstrap and Zurb Foundation are the most popular
among Rails developers. Each adds a library of markup, styles, and standard-
ized web page features such as modal windows, pagination, breadcrumbs, and
navigation.
Bootstrap is the best-known front-end framework. It is the result of an effort
to document and share common design patterns and assets across projects at
Twitter, released as an open source project in August 2011.
Just ahead, we’ll look at why we use Bootstrap in this book. But first, you’ll
need to learn about Sass.
www.dbooks.org
222 CHAPTER 17. FRONT-END FRAMEWORK
preprocessor named Sass. Sass extends CSS to give it more powerful program-
ming language features. As a result, your stylesheets can use variables, mixins,
and nesting of CSS rules, just like a real programming language.
For example, in Sass you can create a variable such as $blue: #3bbfce and
specify colors anywhere using the variable, such as border-color: $blue.
Mixins are like variables that let you use snippets of reusable CSS. Nesting
eliminates repetition by layering CSS selectors.
Sass is included in any new Rails application with the default sass-rails gem.
Bootstrap or Others?
Which front-end framework should you use? Bootstrap or another such as Zurb
Foundation?
The Bootstrap team maintains a Ruby gem that provides a drop-in version of
Bootstrap for Rails. Other front-end frameworks, such as Zurb Foundation, are
also available as Ruby gems. But Bootstrap has a large developer community
and many more third-party projects, as evidenced by a Big Badass List of Use-
ful Twitter Bootstrap Resources. In its sheer magnitude, this list, from Michael
Buckbee and Bootstrap Hero, demonstrates the popularity of Bootstrap and the
vitality of its open source community. We’ll use Bootstrap here because of its
sheer popularity and solid support.
Before I show you how to integrate Bootstrap with your Rails application, let’s
briefly consider matters of design.
Bootstrap 3 or 4?
At the time this was written, the new Bootstrap 4 version was in alpha release.
The Bootstrap 4 version is significantly different from earlier versions. It has
been in alpha for testing and feedback for over a year. Many Rails developers
are already using the Bootstrap 4 version but almost all themes and third-party
add-ons are only available for Bootstrap 3. Eventually, the Bootstrap 4 beta
and final versions will be released but until then, I recommend sticking with
Bootstrap 3. As a beginner, you’ll find more resources and help for Bootstrap
3. We’ll use it here for this tutorial.
www.dbooks.org
224 CHAPTER 17. FRONT-END FRAMEWORK
Bootstrap Gem
Bootstrap provides a standard grid for layout plus dozens of reusable compo-
nents for common page elements such as navigation, forms, and buttons. More
importantly, it gives CSS the kind of structure and convention that makes Rails
popular for back-end development. Bootstrap is packaged as a gem.
In your Gemfile, you’ve already added:
gem 'bootstrap-sass'
With the -force argument, the rails_layout gem will replace existing files.
The gem will create the file:
• app/assets/stylesheets/1st_load_framework.css.scss
• app/assets/javascripts/application.js
• app/views/layouts/_messages.html.erb
• app/views/layouts/_navigation.html.erb
• app/views/layouts/application.html.erb
• app/assets/stylesheets/simple.css
Let’s examine the files to see how our application is configured to use Boot-
strap.
www.dbooks.org
226 CHAPTER 17. FRONT-END FRAMEWORK
You learned earlier that stylesheets can use variables, mixins, and nesting of
CSS rules when you use Sass.
Sass has two syntaxes. The most commonly used syntax is known as “SCSS”
(for “Sassy CSS”), and is a superset of the CSS syntax. This means that every
valid CSS stylesheet is valid SCSS as well. SCSS files use the extension .scss.
The Sass project also offers a second, older syntax with indented formatting
that uses the extension .sass. We’ll use the SCSS syntax.
You can use Sass in any file by adding the file extension .scss. The asset
pipeline will preprocess any .scss file and expand it as standard CSS.
For more on the advantages of Sass and how to use it, see the Sass website or
the Sass Basics RailsCast from Ryan Bates.
Before you continue, make sure that the rails_layout gem renamed the app/assets/stylesheet
file as app/assets/stylesheets/application.css.scss. Otherwise you won’t see
the CSS styling we will apply.
• app/assets/stylesheets/
The asset pipeline helps web pages display faster in the browser by combining
all CSS files into a single file (it does the same for JavaScript).
Let’s examine the file app/assets/stylesheets/application.css.scss:
/*
* This is a manifest file that'll be compiled into application.css, which will include all the
* listed below.
THE APPLICATION.CSS.SCSS FILE 227
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
* vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of t
* compiled file so the styles you add here take precedence over styles defined in any other CSS
* files in this directory. Styles in this file should be added after the last require_* stateme
* It is generally better to create a new file per style scope.
*
*= require_tree .
*= require_self
*/
www.dbooks.org
228 CHAPTER 17. FRONT-END FRAMEWORK
files. CSS that is used on only a single page can go in a file with a name
that matches the page. Or, if sections of the website share common elements,
such as themes for landing pages or administrative pages, make a file for each
theme. How you organize your CSS is up to you; the asset pipeline lets you
organize your CSS so it is easier to develop and maintain. Just add the files to
the app/assets/stylesheets/ folder.
A Manifest File
It’s not obvious from the name of the app/assets/stylesheets/application.css.scss
file that it serves as a manifest file as well as a location for miscellaneous CSS
rules. For most websites, you can ignore its role as a manifest file. In the com-
ments at the top of the file, the *= require_self directive indicates that any
CSS in the file should be delivered to the browser. The *= require_tree .
directive (note the Unix “dot operator”) indicates any files in the same folder,
including files in subfolders, should be combined into a single file for delivery
to the browser.
If your website is large and complex, you can remove the *= require_tree
. directive and specify individual files to be included in the file that is gener-
ated by the asset pipeline. This gives you the option of reducing the size of the
application-wide CSS file that is delivered to the browser. For example, you
might segregate a file that includes CSS that is used only in the site’s adminis-
trative section. In general, only large and complex sites need this optimization.
The speed of rendering a single large CSS file is faster than fetching multiple
files.
Bootstrap JavaScript
Bootstrap provides both CSS and JavaScript libraries.
Like the application.css.scss file, the application.js file is a manifest that al-
lows a developer to designate the JavaScript files that will be combined for
BOOTSTRAP CSS 229
It added the directives //= require jquery and //= require jquery_ujs
to make jQuery available to the application.
Keep in mind that Rails 5.1 dropped jQuery and no longer includes the jquery-
rails gem by default. We added the jquery-rails gem to the Gemfile (and ran
bundle install). Without the jquery-rails gem, you’ll get an error when
you run the application.
The rails_layout command also added the directive //= require bootstrap-sprocket
before //= require_tree . to enable the Bootstrap front-end framework.
Some of the features offered by Bootstrap require the jQuery library which is
why the rails_layout command modifies the app/assets/javascripts/application.js
file.
Bootstrap CSS
The rails_layout gem added a file app/assets/stylesheets/1st_load_framework.css.scss
containing:
www.dbooks.org
230 CHAPTER 17. FRONT-END FRAMEWORK
• buttons
• navigation bar
• alerts
layout and typographic styling. For example, Bootstrap gives you CSS classes
to set up rows and columns in a grid system.
Let’s take a closer look at the Bootstrap grid system.
Bootstrap Grid
The Bootstrap grid is responsive because it has “breakpoints.” There are actu-
ally four grids:
Start by designing for the extra small screen; then add classes prefixed “small,”
“medium,” or “large” if you want a different layout for larger screens. The
layout will change at each breakpoint.
The grid gives you 12 columns by default. You can organize your layout in
horizontal and vertical sections using row and columns classes.
For example, you could use Bootstrap grid classes to set up an application
layout with a footer as a row with two sections:
<div class="container">
<footer class="row">
<section class="col-xs-4">
Copyright 2016
</section>
<section class="col-xs-8">
All rights reserved.
</section>
</footer>
</div>
www.dbooks.org
232 CHAPTER 17. FRONT-END FRAMEWORK
The Bootstrap row class will create a horizontal break. The footer will contain
two side-by-side sections. The first will be four columns wide; the second will
be eight columns wide.
Here’s the same footer with a responsive design:
<div class="container">
<footer class="row">
<section class="col-xs-12 col-sm-4">
Copyright 2016
</section>
<section class="col-xs-12 col-sm-8">
All rights reserved.
</section>
</footer>
</div>
On desktops and tablets, the footer will contain two side-by-side sections. On
phones, each section will expand to take the full browser width, appearing as
stacked rows.
To better understand the grid system with all its options, see the documentation
for the Bootstrap grid.
Suppose your user testing indicates a green button generates more sales. With
the presentational approach you’d have to change both the Rails view file and
the CSS file. With a semantic approach, you’d just change the CSS file to
reassign the color of the submit class.
www.dbooks.org
234 CHAPTER 17. FRONT-END FRAMEWORK
@extend .text-center;
}
.submit {
@extend .btn;
@extend .btn-primary;
@extend .btn-lg;
}
// apply styles to HTML elements
// to make views framework-neutral
main {
@extend .container;
background-color: #eee;
padding-bottom: 80px;
width: 100%;
margin-top: 51px; // accommodate the navbar
}
section {
@extend .row;
margin-top: 20px;
}
The rails_layout gem is in active development so the file you’ve created may
be different from the example in this tutorial. It will probably be very similar.
At the top of the file we import the Bootstrap framework CSS files from the
gem.
We override a Bootstrap style rule so the “Home” navigation link matches the
other links in the navigation bar.
Then we use mixins to create semantic classes.
Mixins can take a block of CSS styles, other mixins, or a CSS selector (a CSS
class or ID).
If you’d like to combine CSS classes, or rename a CSS class, use the @extend
directive.
The first declaration column combines the Bootstrap classes col-md-6 and
text-center to make a new class, column.
Next we create a few classes that combine Bootstrap CSS classes. For example,
the new submit class can be used for a button. When we use it in a view, this
class will be purely semantic since it describes the purpose of the element,
www.dbooks.org
236 CHAPTER 17. FRONT-END FRAMEWORK
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= content_for?(:title) ? yield(:title) : "Learn Rails" %></title>
<meta name="description"
content="<%= content_for?(:description) ? yield(:description) : "Learn Rails" %>">
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload' %>
<%= csrf_meta_tags %>
</head>
<body>
<header>
<%= render 'layouts/navigation' %>
</header>
<main role="main">
FLASH MESSAGES WITH BOOTSTRAP 237
This file is almost identical to the simple application layout file we looked at in
the previous chapter.
Because we’ve applied Bootstrap classes to the HTML element main in the
app/assets/stylesheets/1st_load_framework.css.scss file, there’s no need to
use Bootstrap classes directly in the application layout.
We use each to iterate through the flash hash, retrieving a name and msg that
are passed to a block to be output as a string. The expression if msg.is_a?(String)
serves as a test to make sure we only display messages that are strings.
We construct a div that applies Bootstrap CSS styling around the message.
Bootstrap provides classes alert and alert-dismissible to style the mes-
sage.
www.dbooks.org
238 CHAPTER 17. FRONT-END FRAMEWORK
We use the Ruby ternary operator to check the type of the alert. A class of ei-
ther success or danger styles the message. Rails notice messages will get
styled with the Bootstrap success class. Any other Rails messages, including
alert messages, will get styled with the Bootstrap danger class.
We use the Rails content_tag view helper to create a div containing the
message.
Bootstrap creates a “close” icon by applying the class alert-dismissible.
Bootstrap’s integrated JavaScript library will hide the alert box when the “close”
link is clicked.
Bootstrap provides detailed documentation if you want to change the styling of
the alert boxes.
The navigation partial is now more complex, with layout and Bootstrap classes
needed to produce a responsive navigation bar.
At the conclusion of this chapter, you’ll test the responsive navigation by re-
sizing the window. At small sizes, the navigation links will disappear and be
replaced by an icon labeled “Menu.” Clicking the icon will reveal a vertical
menu of navigation links. The navigation menu is a great demonstration of the
ability of Bootstrap to adjust to the small screen size of a tablet or smartphone.
If you’d like to add a site name or logo to the tutorial application, you can
replace the link helper <%= link_to ’Home’, root_path %>. It is im-
portant to preserve the enclosing layout and classes, even if you don’t want
to display a site name or logo. The enclosing layout is used to generate the
navigation menu when the browser window shrinks to accommodate a tablet or
smartphone.
You’ll see we wrap the nested partial render ’layouts/navigation_links’
with Bootstrap classes to complete the navigation bar.
www.dbooks.org
240 CHAPTER 17. FRONT-END FRAMEWORK
$ rails server
def new
@owner = Owner.new
end
end
GIT 241
Git
Let’s commit our changes to the Git repository and push to GitHub:
$ git add -A
$ git commit -m "front-end framework"
$ git push
www.dbooks.org
242 CHAPTER 17. FRONT-END FRAMEWORK
Chapter 18
Add Pages
Let’s begin adding pages to our web application.
There are three types of web pages in a Rails application. We’ve looked at two
types so far:
There’s another type of web page that is required on many websites. It has
static content; that is, no dynamic data is needed on the page. But it uses the
default application layout to maintain consistency in the website look and feel.
We classify this type of page as a:
Examples include:
• “About” page
• Legal page
243
www.dbooks.org
244 CHAPTER 18. ADD PAGES
• FAQ page
It’s possible to place these pages in the public/ folder and copy the HTML and
CSS from the default application layout but this leads to duplicated code and
maintenance headaches. And dynamic elements such as navigation links can’t
be included. For these reasons, developers seldom create static pages in the
public/ folder.
Alternatively, a dynamic page can be created that has no model, a nearly-empty
controller, and a view that contains no instance variables. This solution is quite
common for static views that use the application layout.
This solution is implemented so frequently that many developers create a gem
to encapsulate the functionality. We’re going to use the best-known of these
gems, the high_voltage gem created by the Thoughtbot consulting firm.
We’ll use the High Voltage gem to create an “About” Page.
We also will create a Contact page. We’ll again use the High Voltage gem,
but only for the first version of the Contact page. Later we’ll discard the page
we created with the High Voltage gem and replace it with a full model-view-
controller implementation. The process will show the difference between an
older form of web application architecture and a newer “Rails way.”
We can add a page using the High Voltage gem almost effortlessly. The gem
implements Rails “convention over configuration” so well that there is nothing
to configure. There are alternatives to its defaults which can be useful but we
won’t need them; visit the GitHub home page for the high_voltage gem if you
want to explore all the options.
In your Gemfile, you’ve already added:
VIEWS FOLDER 245
gem 'high_voltage'
Views Folder
Create a folder app/views/pages:
$ mkdir app/views/pages
Any view files we add to this directory will automatically use the default appli-
cation layout and appear when we use a URL that contains the filename.
The High Voltage gem contains all the controller and routing magic required
for this to happen.
Let’s try it out.
“About” Page
Create a file app/views/pages/about.html.erb:
www.dbooks.org
246 CHAPTER 18. ADD PAGES
Our simple “About” view will be combined with the default application layout
by the High Voltage gem.
We include a content_for Rails view helper that passes a page title to the
application layout.
Contact Page
For the initial version of the Contact page, create a file app/views/pages/contact.html.erb:
The High Voltage gem provides a PagesController. You’ll never see it; it is
packaged inside the gem.
In addition to providing a controller, the High Voltage gem provides default
routing so any URL with the form http://localhost:3000/pages/about will obtain
a view from the app/views/pages directory.
Like the PagesController, the code that sets up the route is packaged inside the
gem. For details about the syntax of routing directives, refer to RailsGuides:
Routing from the Outside In.
UPDATE THE NAVIGATION PARTIAL 247
$ rails server
www.dbooks.org
248 CHAPTER 18. ADD PAGES
Rails.application.routes.draw do
root to: 'visitors#new'
end
Watch what happens when you resize the page. At smaller sizes, the naviga-
tion bar changes to display a menu icon. Clicking the menu icon reveals a
drop-down menu of navigation links. You’re seeing the power of the Bootstrap
framework.
Here’s a troubleshooting tip. If clicking the menu icon doesn’t reveal a drop-
down menu, the application may not be loading the Bootstrap JavaScript li-
brary. Make sure that the file app/assets/javascripts/application.js contains:
Git
Let’s commit our changes to the Git repository and push to GitHub:
$ git add -A
$ git commit -m "add 'about' and 'contact' pages"
$ git push
Contact Form
Forms are ubiquitous on the web, to the degree we seldom notice how often
they are used for data entry, whether we’re logging into a website or posting
a blog comment. To build any interactive website, you’ll need to understand
forms. Here we’ll build a contact form for our tutorial application.
A contact form is common on many websites. If you think about it, contact
forms are often unnecessary; simply displaying an email address is sufficient,
more convenient, and easier to implement. But building a contact form is an
excellent way to learn how to handle user data input. We’ll pretend that our odd
client, Mr. Foobar Kadigan, insists that he needs a contact form on his website.
We’re not backing the tutorial application with a database so we won’t store the
contact data after the information is submitted. Instead, in a subsequent chapter
we’ll learn how to send the contents of the form by email to the website owner.
249
www.dbooks.org
250 CHAPTER 19. CONTACT FORM
we’ll see the approach has limitations. We’ll discard our first approach and
rebuild the Contact page, discovering how the “Rails way” is more powerful.
You may wonder why I’m going to show you two different ways to implement
the contact form.
First, it is worthwhile to see there is more than one way to implement a web
application. Maturity as a software developer means imagining different ap-
proaches and evaluating your options. With this exercise, you’ll contrast two
approaches and see how we make choices about software architecture.
More importantly, it is not always obvious why we do things in a “Rails way.”
It would be easy to simply walk you through the steps to build a contact form
without showing you alternative implementations (that’s how most tutorials do
it). But you’ll gain a deeper understanding of Rails by building the contact form
in a less sophisticated fashion and then seeing the more elegant Rails approach.
User Story
Let’s plan our work with a user story:
*Contact Page*
As a visitor to the website
I want to fill out a form with my name, email address, and some text
In order to send a message to the owner of the website
Our first step will be to create a route to a controller that will process the sub-
mitted form.
Routing
We’re going to create a ContactsController to process the submitted form data.
Every form must have a destination URL that receives the form submission.
ROUTING 251
Rails.application.routes.draw do
post 'contact', to: 'contacts#process_form'
root to: 'visitors#new'
end
$ rails routes
Prefix Verb URI Pattern Controller#Action
contact POST /contact(.:format) contacts#process_form
root GET / visitors#new
page GET /pages/*id high_voltage/pages#show
The output of the rails routes command is somewhat cryptic but confirms
we’ve created the routes we need.
The first item in the rails routes output indicates we can add “contact” to
“_path” to get our route helper, contact_path:
The second item indicates the request will be handled with the HTTP POST
protocol:
The third item indicates the application will respond to the following URL:
www.dbooks.org
252 CHAPTER 19. CONTACT FORM
The fourth item indicates a request to the URL will be handled by:
For details about the syntax of routing directives, refer to RailsGuides: Routing
from the Outside In.
The route won’t work yet; we need to create a ContactsController. But first
we’ll create the form.
Unfortunately, in the quest for simplicity and power, the Rails maintainers have
made forms much more complicated than the original HTML specification. A
large part of the complication is a new forms syntax introduced in Rails 5.1.
Prior to Rails 5.1, Rails provided two different ways to create forms. One
approach, using the form_tag directive, was simpler and didn’t use a form
builder and associated model. The second approach, using the form_for di-
rective, was more powerful and widely used because it enabled validation of
form data using an associated model. In Rails 5.1, the Rails maintainers in-
troduced a third approach, using the form_with directive. The form_with
approach replaces both the form_tag and form_for directives, combining
both earlier approaches in one set of view helpers.
There is very little documentation to explain how to use the form_with ap-
proach. As of this writing, the RailsGuides: Rails Form Helpers official docu-
ment has not been updated for the new form_with syntax. Most tutorials (and
Stack Overflow answers) explain forms using the form_tag or form_for
helpers. The only official documentation is the Rails API document. These
are persuasive reasons not to use the new form_with syntax. However, a
future version of Rails will deprecate (remove) the form_tag or form_for
helpers. It’s best to learn to use form_with for your forms. Our tutorial will
use form_with.
Replace the contents of the file app/views/pages/contact.html.erb:
www.dbooks.org
254 CHAPTER 19. CONTACT FORM
The form_with view helper instantiates a form builder object which we as-
sign to a variable named form. The form builder offers many standard form
elements, such as text fields and submit buttons. Each element is available as a
method call on the form object.
The view helper form_with requires parameters and a block.
Every form needs a URL that will handle processing of the form data. In this
case, we specify a route in the application:
Later, when we change this form to accommodate the”Rails way,” we’ll replace
these two parameters with a single instance variable. The magic of Rails will
generate the name of the form and the destination URL from the instance vari-
able. For now, to implement the “old way,” we simply supply the destination
URL.
The form_with view helper accommodates a Ruby block. The block begins
with do and closes with end. The code inside the block works just like code in-
side a method. In this case, the form object is passed to the block and methods
belonging to the form object are called to produce HTML output.
CONTROLLER 255
Inside the block, the form object methods generate HTML for:
• a name field
• an email field
• a submit button
The structure of the form is clearly visible in the code. The form begins with
a form_with helper and closes with the end keyword. Each line of code
produces an element in the form such as a field or a button.
This is a common structure for a Rails view helper and it will soon become
familiar.
Controller
We need code to process the form data. The form data is sent to the server
as a POST request attached to a URL. As we’ve learned, in Rails we use con-
trollers to respond to browser requests. For this implementation, we’ll create a
ContactsController to process the submitted form data.
Create a file app/controllers/contacts_controller.rb:
def process_form
Rails.logger.debug "DEBUG: params are #{params.inspect}"
www.dbooks.org
256 CHAPTER 19. CONTACT FORM
end
Params Hash
Take a close look at these two lines:
The full params hash actually contains more data which we can see with a
debug command:
CONTROLLER 257
• form data
• current controller
• current action
You will see the contents of the params hash in the console log after you sub-
mit the form. We’ll look at the console log when we test the implementation.
Process_form Method
Now that we know about the params hash, take a look again at the process_form
method:
def process_form
Rails.logger.debug "DEBUG: params are #{params.inspect}"
flash[:notice] = "Received request from #{params[:name]}"
redirect_to root_path
end
We use a logger.debug method to reveal the form data in our console log by
revealing the contents of the params hash. The inspect method shows the
parameters in an easy-to-read list.
www.dbooks.org
258 CHAPTER 19. CONTACT FORM
Then we extract the data posted to the name field of the form and construct
a flash message. A hash containing the data from the contact form is nested
inside the params hash. We can retrieve the value of the name field with the
expression params[:name]. We use double quotes and string interpolation to
form the message using the #{...} syntax that evaluates a Ruby expression
and combines it with a string.
Finally we use the redirect_to directive to render the home page.
We haven’t actually sent the contact data to anyone. We’ll add code for that
later, after we refactor the controller to be a better example of the “Rails way.”
Before we do that, let’s test the current implementation. We’ve already set up
routing for the new controller.
$ rails server
The console log is our most important tool for debugging. Let’s analyze what
we see:
• at . . . - timestamp
• process_form - the controller action (the method that handles the request)
www.dbooks.org
260 CHAPTER 19. CONTACT FORM
That’s a lot of data. For now, we really only care about the form data buried in
the params hash.
You can see that we really don’t need the debug message because the console
log shows us the contents of the params hash.
def process_form
if params[:name].blank?
raise 'Name is blank!'
REMOVE THE CONTACT PAGE 261
end
if params[:email].blank?
raise 'Email is blank!'
end
if params[:content].blank?
raise 'Message is blank!'
end
message = "Received request from #{params[:name]}"
redirect_to root_path, :notice => message
end
end
We would need additional code to test for invalid email addresses (it will be
a complex regex, or regular expression). And we would need a nicer way
of showing the error to the visitor (right now, raising the exception displays
an error message that makes it appear the application is broken). If we were
implementing this on another web application platform, we might go further
down this path, googling for code examples, and implementing a lengthy but
bulletproof validation function.
Rails offers a better way.
$ rm app/views/pages/contact.html.erb
www.dbooks.org
262 CHAPTER 19. CONTACT FORM
Our initial implementation of the contact form is consistent with the earliest
approach to web application development. That’s why I call it the “old way.”
It is an approach that originated in 1993 with a specification for CGI, the Com-
mon Gateway Interface. Before CGI, every page on the web existed only as a
static HTML file. CGI made it possible to run a program, or CGI script, that
dynamically generated HTML. In the early years of the web, every web URL
matched either an HTML file or a CGI script. This is the “page paradigm” of
the web.
So far, we’re following the “page paradigm.” Our Contact page hosts the form.
Clicking the submit button makes a request to another page that is actually a
program that returns HTML. Until the late 1990s, this is how the web worked.
But soon after the introduction of CGI, developers began exploring the possi-
bility of running a single program (an application server) that responds to any
URL, parsing the URL to establish routing, and generating pages dynamically.
This was the genesis of the “web application paradigm.” It’s how Rails works.
The web application paradigm frees us from one-to-one correspondence of a
URL with a single file or script. It allows us to refactor our code into object-
oriented classes and methods that can be inherited rather than duplicated, which
means we don’t repeat the same code on every page that processes a form.
The web application paradigm makes it possible to use the model-view-controller
architecture. Instead of looking at the web as URLs that return pages, we see
requests that are routed to controllers that render views. We can segregate any
code that manipulates data into a model class, instead of mixing HTML with
data manipulation in a single script. With the “web application paradigm,” we
can have a generic model class that isolates the code that connects to a database
or validates form data. We can create models that inherit the generic behavior
from a parent class and get a database connection or validation “for free.” Un-
like the “page paradigm,” we’ll avoid duplicating validation code every time
we need to process a form.
Consider our process_form method again:
ACTIVEMODEL 263
def process_form
if params[:name].blank?
raise 'Name is blank!'
end
if params[:email].blank?
raise 'Email is blank!'
end
if params[:content].blank?
raise 'Message is blank!'
end
message = "Received request from #{params[:name]}"
redirect_to root_path, :notice => message
end
end
ActiveModel
Rails extracts and generalizes common code that every website requires. The
code that websites need for access to databases is abstracted into the Rails
ActiveRecord class. ActiveRecord includes code from the ActiveModel class
that handles interaction with forms and data validation.
The ActiveModel class interfaces with SimpleForm to provide sophisticated
validation and error handling. We can mix in behavior from the ActiveModel
class to add validation and error handling to any model we create.
SimpleForm will recognize ActiveModel methods if we provide a model as
www.dbooks.org
264 CHAPTER 19. CONTACT FORM
an argument to the SimpleForm view helper. SimpleForm will give the form
a name that matches the model name. And SimpleForm will automatically
generate a destination URL for the form based on the model name.
More significantly, SimpleForm will add sophisticated error handling to the
form. If a visitor doesn’t enter a name or submits an invalid email address, and
we declare in our model that we require validation, SimpleForm will highlight
the invalid field and display an inline message indicating the problem. Com-
pared to what we’ve implemented so far, this kind of error handling provides a
vastly superior user experience. Instead of displaying a message that the appli-
cation failed, the form will be redisplayed with the problem marked and noted.
Now that we’ve seen the advantages of the “Rails way,” let’s re-implement our
contact form using the model-view-controller architecture.
Model
When we build database-backed applications with Rails, we base our models
on a parent class named ActiveRecord. We are not using a database for our
tutorial application, so we’ll mix in behavior from ActiveModel, which adds
validation and error handling to our model. Let’s set up a model that doesn’t
require a database.
Create a file app/models/contact.rb:
class Contact
include ActiveModel::Model
attr_accessor :name, :email, :content
validates_presence_of :name
validates_presence_of :email
validates_presence_of :content
validates_format_of :email,
with: /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i
validates_length_of :content, :maximum => 500
end
CREATE A NEW CONTACT PAGE 265
When you copy this, be careful to keep the long regex expression (with:
/.../i) on one line (no line breaks).
We give the model the name “Contact.”
We mix in behavior from the ActiveModel class using include ActiveModel::Model.
We create attributes (data fields) for the model by using the attr_accessor
keyword. The attributes match the fields in the contact form. If we were using a
database for our tutorial application, we would not need to use attr_accessor
because ActiveRecord would create access methods for reading and writing at-
tributes directly from the database.
ActiveModel gives us validation methods named validates_presence_of,
validates_format_of, and validates_length_of. We check that name,
email, and content exist (no blanks are allowed). We provide a complex
regex, or regular expression, to test if the email address is valid. Finally, we
declare that the message content cannot exceed 500 characters.
The model is elegant. We describe the fields we need and state our validation
requirements. ActiveModel does all the rest.
Next we’ll add a new Contact page by creating a view in the app/views/contacts/
folder.
The new contact form will use our new model.
$ mkdir app/views/contacts/
www.dbooks.org
266 CHAPTER 19. CONTACT FORM
The form is the same as we used before, but we’re now providing only one ar-
gument, the @contact instance variable, to the form_with view helper. That’s
enough to generate the form name and destination URL.
We haven’t yet created a controller that assigns the Contact model to the @contact
instance variable. We’ll do that soon.
The form helper uses the @contact instance variable to name the form, set
a destination for the form data, and initialize each field in the form using at-
tributes from the Contact model. Setting the values for the form fields from the
attributes in the model is called “binding the form to the object” and you can
read about it in the RailsGuides: Form Helpers article.
We’ve added the error_notification method which provides all the error
handling. The method call is very simple but the results will be impressive.
We’ll need a controller and routing to complete our model-view-controller ar-
chitecture. But first, we’ll detour to learn about seven standard controller ac-
tions.
SEVEN CONTROLLER ACTIONS 267
You can manage any list using these seven actions. There are a few extra actions
that are helpful, such as:
But seven basic actions are all you need for managing any list of items.
The “Rails way” is about taking advantage of structure and convention to lever-
age the power of the framework.
www.dbooks.org
268 CHAPTER 19. CONTACT FORM
Controller
Replace the contents of the file app/controllers/contacts_controller.rb:
def new
@contact = Contact.new
end
def create
@contact = Contact.new(secure_params)
if @contact.valid?
# TODO send message
flash[:notice] = "Message sent from #{@contact.name}."
redirect_to root_path
else
render :new
end
end
private
def secure_params
params.require(:contact).permit(:name, :email, :content)
end
end
We’ve dropped the “old school” process_form method and added the “Rails
way” new and create methods.
The controller new action will instantiate an empty Contact model, assign it to
the @contact instance variable, and render the app/views/contacts/new.html.erb
www.dbooks.org
270 CHAPTER 19. CONTACT FORM
view. We’ve already created the view file containing the form.
SimpleForm will set a destination URL that corresponds to the ContactsCon-
troller#create action. The create method will instantiate a new Contact model
using the data from the form (we take steps to avoid security vulnerabilities
first—more on that later).
The ActiveModel class provides a method valid? which we can call on the
Contact model. Our conditional statement if @contact.valid? checks
each of the validation requirements we’ve set in the model.
If all the Contact fields are valid, we can send a message (which we’ll add later),
prepare a flash message, and redirect to the home page. Notice that we don’t
need to dig into the params hash for the visitor’s name; it is now available as
@contact.name directly from the model.
If any validation fails, the controller create action will render the app/views/contacts/new.
view. This time, appropriate error messages are set and the form object’s
error_notification method will highlight the invalid field and display a
matching prompt.
You’re looking at the tightly bound interaction of the “Rails way” model, view,
and controller.
The only element we are missing is routing. But first, let’s look closer at the
steps we take to avoid security exploits.
Mass-Assignment Vulnerabilities
With this code, we make sure that params[:contact] only contains :name,
:email, :content. If other parameters are present, they are stripped out.
Rails will raise an error if a controller attempts to pass params to a model
method without explicitly permitting attributes via permit.
In older versions of Rails (before Rails 4.0), the mass-assignment exploit was
blocked by using a “white list” of acceptable parameters with the attr_accessible
keyword in a model. You’ll see this code in examples and tutorials that were
written before Rails 4.0 introduced “strong parameters” in the controller.
Private Methods
If you paid close attention to the code you added to the Contacts controller, you
may have noticed the keyword private above the secure_params method
definition. This is a bit of software architecture that limits access to the secure_params
method (plus any more methods we might add beneath it).
Very simply, adding the private keyword restricts access to the secure_params
method so only methods in the same class can use it. You might be puzzled;
after all, how else could it be accessed? We haven’t explored calling meth-
ods from other classes, so I’ll just say that without the private keyword, the
secure_params method could be used from code anywhere in our applica-
tion. In this case, we apply the private keyword because we want to be
sure the secure_params method is only used in the ContactsController
class. It’s just a bit of “best practice” and for now, you can simply learn that
secure_params method should be a private method.
www.dbooks.org
272 CHAPTER 19. CONTACT FORM
Now let’s look at routing for controllers that are built the “Rails way.”
Routing
Rails routing is aware of the seven standard controller actions.
In fact, it takes only one keyword (with one parameter) to generate seven dif-
ferent routes for any controller.
The keyword is resources and supplying a name that matches a model and
controller provides all seven routes.
Open the file config/routes.rb. Replace the contents with this:
Rails.application.routes.draw do
resources :contacts, only: [:new, :create]
root to: 'visitors#new'
end
You can run the rails routes command to see these in the console:
$ rails routes
Prefix Verb URI Pattern Controller#Action
contacts POST /contacts(.:format) contacts#create
new_contact GET /contacts/new(.:format) contacts#new
root GET / visitors#new
page GET /pages/*id high_voltage/pages#show
The output of the rails routes command shows we’ve created the routes
we need.
Our new route new_contact_path can now be used. We’ve completed our
move to the model-view-controller architecture by adding the appropriate routes.
www.dbooks.org
274 CHAPTER 19. CONTACT FORM
$ rails server
Git
Let’s commit our changes to the Git repository and push to GitHub:
GIT 275
$ git add -A
$ git commit -m "contact form"
$ git push
www.dbooks.org
276 CHAPTER 19. CONTACT FORM
Chapter 20
Send Mail
Email sent from a web application is called transactional email. As a website
visitor, you’ve probably seen transactional email such as these messages:
A web application can send email to a visitor. It can also send messages to its
owner or webmaster. On large active sites, email notices can be impractical (an
admin interface is better) but for our small-volume tutorial application, it makes
sense to email the contact request directly to the site owner (Foobar Kadigan is
retired and enjoys receiving email).
User Story
Let’s plan our work with a user story:
277
www.dbooks.org
278 CHAPTER 20. SEND MAIL
To implement the user story, let’s create a feature that sends the contact data as
an email message.
Implementation
Rails makes it easy to send email. The ActionMailer gem is part of any Rails
installation.
Implementation of email closely follows the model-view-controller architec-
ture. To implement email, you’ll need:
• model
• view
• mailer
The Rails directory structure already gives us a folder app/mailers/ for the
mailer class and, not surprisingly, it is a sibling of the app/controllers/ folder.
We don’t have to create the necessary folders and files manually, as the rails
generate command runs a utility to create what we need.
The name of the mailer isn’t important; we’ll use UserMailer because it is
obvious.
The rails generate command will create a file:
• app/mailers/user_mailer.rb
• app/mailers/application_mailer.rb
• app/views/layouts/mailer.html.erb
• app/views/layouts/mailer.text.erb
www.dbooks.org
280 CHAPTER 20. SEND MAIL
def contact_email(contact)
@contact = contact
mail(to: Rails.application.secrets.owner_email, from: @contact.email, :subject => "Website C
end
end
For our contact_email method, we’ll insert the email address of the visitor
as the “from” address since we are sending a message to the site owner. This
makes it easy for Foobar Kadigan to click “reply” when he is reading the con-
tact messages in his inbox. You can see our use of the email attribute from the
Contact model in the expression from: @contact.email.
That’s all we need for mailer class. Next we’ll create a view containing the
message.
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
</head>
<body>
<h1>Website Contact</h1>
<p>
This visitor requested contact:
</p>
<p>
<%= @contact.name %><br/>
<%= @contact.email %><br/>
www.dbooks.org
282 CHAPTER 20. SEND MAIL
</p>
<p>
The visitor said:
</p>
<p>
"<%= @contact.content %>"
</p>
</body>
</html>
You can easily imagine how this view would look as a web page. You’ll soon
see it as an email message in your inbox.
For those recipients who like plain text, create a view without HTML markup.
Create a file app/views/user_mailer/contact_email.text.erb:
You received a message from <%= @contact.name %> with email address <%= @contact.email %>.
Modify Controller
We’ll add code to the ContactsController:
UserMailer.contact_email(@contact).deliver_now
def new
@contact = Contact.new
end
def create
@contact = Contact.new(secure_params)
if @contact.valid?
UserMailer.contact_email(@contact).deliver_now
flash[:notice] = "Message sent from #{@contact.name}."
redirect_to root_path
else
render :new
end
end
private
def secure_params
params.require(:contact).permit(:name, :email, :content)
end
end
$ rails server
www.dbooks.org
284 CHAPTER 20. SEND MAIL
Troubleshooting
If you get an error, you can practice troubleshooting. You’ve set up a complex
system with many dependencies. It’s great if it works, but there are several
opportunities for errors.
The most likely errors are a missing user name or password. We are trying
to connect to the SendGrid email service. SendGrid expects your SendGrid
user name. Mine is DanielKehoe (it is not my email address). SendGrid also
expects a password.
$ echo "$SENDGRID_USERNAME"
Password Issues
If you get the error message, “SMTP-AUTH requested but missing secret phrase,”
SendGrid is not receiving the SendGrid password.
Check that the SendGrid password is set in your Unix environment variables:
$ echo "$SENDGRID_PASSWORD"
You should see the long cryptic string in the console response. Again, make
sure you’ve used underscores consistently, and SENDGRID_PASSWORD is used
for the Unix environment variable as well as the config/secrets.yml file.
development:
email_provider_username: <%= ENV["SENDGRID_USERNAME"] %>
email_provider_password: <%= ENV["SENDGRID_PASSWORD"] %>
www.dbooks.org
286 CHAPTER 20. SEND MAIL
with:
development:
email_provider_username: example
email_provider_password: 's#cr*t'
In a YAML file, you do not need quotes unless your string contains special
characters. If your password contains any of these characters you should sur-
round the string with single quotes:
Remember the security rule: Don’t commit the config/secrets.yml file to Git
if it contains any secrets. Test the application and finish your troubleshoot-
ing. Then remove the hardcoded values from the config/secrets.yml file before
committing to Git.
Asynchronous Mailing
You may notice a delay in the responsiveness of the Contact form after adding
the email feature. Unfortunately, there’s a performance penalty with our new
feature. Our controller code connects to the SendGrid server and waits for a
response before it renders the home page and displays the acknowledgment
message.
The performance penalty can be avoided by changing the implementation so
that the controller doesn’t wait for a response from the SendGrid server. We
call this asynchronous behavior because sending email does not need to be
“in sync” with displaying the acknowledgment. Eliminating a delay improves
the user experience and makes the site feel more responsive. Asynchronous
mailing requires a queueing system for background jobs.
GIT 287
For our tutorial application, and for a typical small business website, the delay
caused by lack of queueing is no big deal. Keep in mind, though, as you tackle
bigger projects in Rails, you will need to implement a queueing system. Rails
includes the Active Job feature for background processing. The Mailing List
with Active Job tutorial in the Capstone Rails Tutorials series explains how to
use it.
Git
Let’s commit our changes to the Git repository and push to GitHub:
$ git add -A
$ git commit -m "sending mail"
$ git push
You’ve created a Rails application that handles a form and sends email to the
site owner.
Mail is a practical way to connect with site visitors. Let’s implement a feature
that collects email addresses for mass mailing of a newsletter.
www.dbooks.org
288 CHAPTER 20. SEND MAIL
Chapter 21
Mailing List
Even as other messaging avenues become increasingly popular, such as mes-
saging apps or Facebook messages, email remains the most practical way to
stay in touch with website visitors. Encouraging a visitor to provide an email
address means offering an invitation to a dialog and a relationship beyond a
single visit.
If you have a legitimate reason to stay in touch, and you’ve motivated the visitor
to leave an email address, you’ll need a mailing list service. You’ve seen how
Rails can send an email message. From what you’ve seen so far, you can imag-
ine it would not take much code to loop through a list of email addresses from
a database, sending a message to each. In the early days of the web, it was easy
for any system administrator to write a script for mass mailings. Since there is
negligible cost to sending bulk email, unscrupulous and ignorant operators sent
email to any address they could scrape, borrow, or steal. The resulting flood
of spam made checking one’s inbox an icky experience and destroyed much of
the early culture of the Internet. Fortunately, services such as Gmail arose to
filter email. There is now a thick (but leaky) layer of screening protocols that
redirect spam to a junk folder. One reason you won’t use a Rails application
to send bulk email is that a web application server is not the most efficient tool
for sending email. More significantly, there’s a good chance your email won’t
go through or, if it does (and someone complains), you’ll quickly see your IP
289
www.dbooks.org
290 CHAPTER 21. MAILING LIST
address blacklisted. That’s why we use mailing list services to send bulk email
such as newsletters or promotional offers.
Considerable expertise is required to keep email from being filtered as spam
(see MailChimp’s article Email Delivery For IT Professionals. Email service
providers increase reliability of delivery. These services track deliveries and
show how well your email is being delivered. You’ll also get features such
as management of “unsubscribe” requests and templates to design attractive
messages.
There are at least a dozen well-established email service providers that allow
a Rails application to programmatically connect to the service (via an API) to
add or remove email addresses. For a list, see the article Send Email with Rails.
For this tutorial application, we’ll use MailChimp because there is no cost to
open an account and you can send up to 12,000 emails/month to list of 2000 or
fewer subscribers for free.
Spam is unsolicited email. Don’t ever send spam, whether for yourself, a client,
or an employer. If recipients complain, your IP address and domain name will
be blacklisted. So be very careful to only send to subscribers who signed up,
send what subscribers expect, and be sure to offer value. If you get complaints,
or the unsubscribe rate is high, stop.
We’ll assume we’ve discussed the rules with Foobar Kadigan and he is eager
to offer a newsletter to his visitors that will be genuinely appreciated.
User Story
Let’s plan our work with a user story:
Implementation
We’ll use the Rails model-view-controller architecture. We’ll need:
• Visitors model
We’ll add a Visitor model that has a data attribute for an email address. We
already have a Visitors controller that renders the home page using the file in
the app/views/visitors/ folder. We’ll replace the contents of the view file with
a nice photo, a marketing message, and a form.
Our Visitors controller new and create methods will be very similar to what
we created for the Contacts controller. Instead of connecting to SendGrid to
send a message, we’ll call a method to save the visitor’s email address to a
MailChimp mailing list.
Gibbon Gem
The Gibbon gem is a convenient wrapper for the MailChimp API. We could
connect to the MailChimp API using other gems that provide low-level plumb-
ing such as HTTP connections (httparty) and data parsing (multi_json), but
other developers have already done the work of wrapping the plumbing in a
higher-level abstraction that easily fits into a Rails application. Amro Mousa’s
Gibbon gem is popular and actively maintained.
www.dbooks.org
292 CHAPTER 21. MAILING LIST
gem 'gibbon'
Home Page
Earlier we built a home page that provided a simple demonstration of the Ruby
language. We’ll discard it and replace it with a page that you could adapt for a
typical small-business website.
We want a nice photo, space for a marketing message, and the “sign up” form.
Replace the contents of the file app/views/visitors/new.html.erb:
We include content_for view helpers that pass a title and description to the
application layout.
HOME PAGE 293
We add a photo to the page with an <img> tag. We’re taking a shortcut and
using a placeholder photo from the lorempixel.com service.
The section and <div class="column"> tags apply our CSS grid to cre-
ate a row with two columns, one for our marketing message, and one for the
form.
Our marketing message is merely a placeholder. For a real website, you’d likely
craft a stronger call to action than merely “Stay in touch.”
The form is very similar to the form on the Contact page, except we initialize it
with the @visitor instance variable and only need a field for an email address.
We use the :placeholder parameter to create a hint in the empty input field.
A submit element will contain the text, “Sign up for the newsletter,” and we
apply a CSS class to style the element as a button.
Photo Options
You’re free to modify this page as you wish, as long as you keep the form intact.
You might wish to modify the placeholder photo. If you don’t like cats, try
http://lorempixel.com/1170/600/nightlife/1 or any other categories from the lorem-
pixel.com service. You can change the size by modifying the dimensions from
1170 (pixel width) by 600 (pixel height).
You can replace the placeholder photo with your own. Look for the app/assets/images
folder and add an image. Instead of the HTML <img> tag, use the Rails
image_tag view helper, like this:
www.dbooks.org
294 CHAPTER 21. MAILING LIST
Visitor Model
The Visitor model is almost identical to the Contact model we created earlier,
except there is just one data attribute for the email field.
We’ll also add a subscribe method to add a visitor to a MailChimp list. We’ll
call this method from the controller when we process the submitted form.
Create a file app/models/visitor.rb:
class Visitor
include ActiveModel::Model
attr_accessor :email
validates_presence_of :email
validates_format_of :email, with: /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i
def subscribe
mailchimp = Gibbon::Request.new(api_key: Rails.application.secrets.mailchimp_api_key)
list_id = Rails.application.secrets.mailchimp_list_id
result = mailchimp.lists(list_id).members.create(
body: {
email_address: self.email,
status: 'subscribed'
})
Rails.logger.info("Subscribed #{self.email} to MailChimp") if result
end
end
When you copy this, be careful to keep the long regex expression with:
/.../i on one line (no line breaks).
Just as we did for the Contact model, we use include ActiveModel::Model
to mix in behavior from the ActiveModel class. This is the best way to create a
model that does not use a database. In other applications, where models use a
database, you will create a model class that inherits from ActiveRecord instead.
We create the email attribute using the attr_accessor keyword. We set vali-
dation requirements using validates_presence_of and validates_format_of
keywords.
To subscribe a visitor to a mailing list, you need to provide:
VISITORS CONTROLLER 295
Visitors Controller
We already have a Visitors controller that contains a simple new method. We’ll
change the new method, add a create method, and provide a secure_params
private method to secure the controller from mass assignment exploits.
www.dbooks.org
296 CHAPTER 21. MAILING LIST
def new
@visitor = Visitor.new
end
def create
@visitor = Visitor.new(secure_params)
if @visitor.valid?
@visitor.subscribe
flash[:notice] = "Signed up #{@visitor.email}."
redirect_to root_path
else
render :new
end
end
private
def secure_params
params.require(:visitor).permit(:email)
end
end
Our new method now assigns the Visitor model to an instance variable instead
of the Owner model.
The create method is almost identical to the Contacts controller create
method. We instantiate the Visitor model with scrubbed parameters from the
submitted form.
If the validation check succeeds, we subscribe the visitor to the MailChimp
mailing list with the @visitor.subscribe method. All the work of con-
necting to MailChimp happens in the Visitor model.
If the validation check fails, we redisplay the home page (the new action).
CLEAN UP 297
Clean Up
We no longer use the Owner model, so we can delete the file app/models/owner.rb:
$ rm app/models/owner.rb
Routing
Our routing is now more complex. In addition to rendering the visitors# new
view as the application root (the home page), we need to handle the create
action. We can use a “resourceful route” as we did with the Contacts controller.
Open the file config/routes.rb. Replace the contents with this:
Rails.application.routes.draw do
resources :contacts, only: [:new, :create]
resources :visitors, only: [:new, :create]
root to: 'visitors#new'
end
www.dbooks.org
298 CHAPTER 21. MAILING LIST
You can run the rails routes command to see these in the console:
$ rails routes
Prefix Verb URI Pattern Controller#Action
contacts POST /contacts(.:format) contacts#create
new_contact GET /contacts/new(.:format) contacts#new
visitors POST /visitors(.:format) visitors#create
new_visitor GET /visitors/new(.:format) visitors#new
root GET / visitors#new
page GET /pages/*id high_voltage/pages#show
The output of the rails routes command shows we’ve created the routes
we need.
TEST THE APPLICATION 299
$ rails server
Git
Let’s commit our changes to the Git repository and push to GitHub:
www.dbooks.org
300 CHAPTER 21. MAILING LIST
$ git add -A
$ git commit -m "mailing list"
$ git push
Deploy
You’ve been running the default web server on your local machine. If you
wanted, you could leave your computer running, set up a managed DNS ser-
vice, and your web application would be accessible to anyone. But even if
you wanted to leave your computer running 24 hours a day, you’re probably
not a security expert, your web server isn’t tuned to handle much traffic, and
your computer is distant from the interconnection hubs where most websites
are hosted. For these reasons, when we move a web application from devel-
opment to production, we deploy it to a web hosting service that provides a
hosting platform on a server located in a strategically-located data center.
Data centers offer colocation services, renting rack-mounted computers with
fast Internet connections that can be configured as web servers. In the early
days of the web, deploying a web application required system administration
skills to configure and maintain a web server. Today, some developers like to
set up their web servers “from bare metal” using virtual private servers from
Linode, Slicehost, Rackspace, Amazon EC2, or others. With sufficent skills
and study, they say there is a feeling of satisfaction from doing it yourself.
But not everyone wants to be a system administrator. Most Rails developers
simply use a hosted platform as a service (PaaS) provider such as Heroku,
DigitalOcean, EngineYard, OpenShift, or Pivotal Cloud Foundry.
If you’ve previously built web sites, you may already be using a shared web
301
www.dbooks.org
302 CHAPTER 22. DEPLOY
Heroku Costs
It costs nothing to set up a Heroku account and deploy as many applications as
you want. You’ll pay only if you upgrade your hosting to accommodate a busy
website.
Heroku pricing is based on a measure of computing resources the company
calls a “dyno.” Think of a dyno as a virtual server (though it is not). For
personal projects, you can run your Rails application on a single dyno and
never incur a charge, as long as it is not active more than 12 hours a day.
A single dyno idles after one hour of inactivity, “going to sleep” until it receives
a new web request. For a personal project, this means your web application will
respond with a few seconds delay if it hasn’t received a web request in over an
hour. After it wakes up, it will respond quickly to every browser request.
If you want your web application running 24 hours per day and responding to
every request without delay, Heroku will charge $7 per month for a “hobby”
account. You’ll be able to set up a custom domain, using your own domain
name. Heroku offers the option of adding dynos to handle more traffic for $25
TEST THE APPLICATION 303
For this tutorial application, we won’t concern ourselves with the possibility
that the website may get a lot of traffic. I’m sure you’ll join me in offering
hearty thanks to Heroku for providing a convenient service that beginners can
use for free.
Let’s deploy!
www.dbooks.org
304 CHAPTER 22. DEPLOY
Gemfile
We need to modify the Gemfile for Heroku.
We add a group :production block for a gem that Heroku needs:
• pg - PostgreSQL gem
Heroku doesn’t support the SQLite database; the company provides a Post-
greSQL database. Though we won’t need it for our tutorial application, we
must include the PostgreSQL gem for Heroku. We’ll mark the sqlite3 gem to
be used in development only.
Open your Gemfile and replace the contents with the following:
Gemfile
source 'https://rubygems.org'
ruby '2.4.1'
gem 'rails', '~> 5.1.2'
# Rails defaults
gem 'sqlite3'
gem 'puma', '~> 3.7'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
group :development, :test do
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'capybara', '~> 2.13'
gem 'selenium-webdriver'
end
group :development do
gem 'web-console', '>= 3.3.0'
PREPARING FOR HEROKU 305
# learn-rails
gem 'bootstrap-sass'
gem 'gibbon'
gem 'high_voltage'
gem 'jquery-rails'
group :development do
gem 'better_errors'
gem 'rails_layout'
gem 'sqlite3'
end
group :production do
gem 'pg'
end
We have to run bundle install because we’ve changed the Gemfile. The
gem we’ve added is only needed in production so we don’t install it on our local
machine. When we deploy, Heroku will read the Gemfile and install the gem in
the production environment. We’ll run bundle install with the -without
production argument so we don’t install the new gem locally:
You’ll see:
.
.
.
Gems in the group production were not installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.
Let’s commit our changes to the Git repository and push to GitHub:
www.dbooks.org
306 CHAPTER 22. DEPLOY
$ git add -A
$ git commit -m "gems for Heroku"
$ git push
To block all search engine spiders, remove the commenting from the User-Agent
and Disallow lines.
You can learn more about the format of the robots exclusion standard.
Humans.txt
Many websites include a robots.txt file for nosy bots so it’s only fair that you
offer a humans.txt file for nosy people. Few people will look for it but you can
add a file public/humans.txt to credit and identify the creators and software
behind the website. The HTML5 Boilerplate project offers an example file or
you can borrow from RailsApps.
www.dbooks.org
308 CHAPTER 22. DEPLOY
Heroku Toolbelt
Heroku provides a command line utility for creating and managing Heroku
apps.
Visit https://toolbelt.heroku.com/ to install the Heroku Toolbelt. A one-click
installer is available for Mac OS X, Windows, and Linux.
The installation process will install the Heroku command line utility. It also
installs the Foreman gem which is useful for duplicating the Heroku production
environment on a local machine. The installation process will also make sure
Git is installed.
To make sure the Heroku command line utility is installed, try:
$ heroku version
heroku-toolbelt/...
$ heroku login
Enter your Heroku credentials.
Email: [email protected]
Password:
Could not find an existing public key.
Would you like to generate one? [Yn]
Generating new SSH public key.
Uploading ssh public key /Users/adam/.ssh/id_rsa.pub
The Heroku command line utility will create SSH keys if necessary to guaran-
tee a secure connection to Heroku.
Heroku Create
Be sure you are in your application root directory and you’ve committed the
tutorial application to your Git repository.
Use the Heroku create command to create and name your application.
Replace myapp with something unique. Heroku demands a unique name for
every hosted application. If it is not unique, you’ll see an error, “name is al-
ready taken.” Chances are, “learn-rails” is already taken.
The name must start with a letter and can only contain lowercase letters, num-
bers, and dashes.
If you don’t specify your app name (myapp in the example above), Heroku
will supply a placeholder name. You can easily change Heroku’s placeholder
name to a name of your choice with the heroku apps:rename command
(see Renaming Apps from the CLI).
Don’t worry too much about getting the “perfect name” for your Heroku app.
The name of your Heroku app won’t matter if you plan to set up your Heroku
www.dbooks.org
310 CHAPTER 22. DEPLOY
app to use your own domain name. You’ll just use the name for access to
the instance of your app running on the Heroku servers; if you have a custom
domain name, you’ll set up DNS (domain name service) to point your domain
name to the app running on Heroku.
The heroku create command sets your Heroku application as a Git remote
repository. That means you’ll use the git push command to deploy your
application to Heroku.
Enable Email
You’ll need to enable email for production or else you’ll get errors when your
application tries to send email from Heroku.
To use SendGrid, add the following to your config/environments/production.rb
file:
You can use port 25, 587, or 2525 (some ISPs restrict connections on port 25).
Be sure to add the new settings before the end keyword in the file. The settings
can be added anywhere, as long as they precede the end keyword!
SET HEROKU ENVIRONMENT VARIABLES 311
You’ll need to specify the unique name you’ve selected for your hosted ap-
plication. We’re using the Rails.application.secrets.domain_name
configuration variable in two places in the file. The config/secrets.yml file
provides configuration variables for use in production.
Be sure to commit your code to the Git local repository:
$ git add -A
$ git commit -m "email set for Heroku"
$ git push
Don’t use the values shown above. Instead, look in your .bash_profile or
.bashrc files and copy the values you find there.
When you set myapp.herokuapp.com, replace myapp with the name that
Heroku is using for your application. If you want to use a custom domain name,
www.dbooks.org
312 CHAPTER 22. DEPLOY
you’ll need to set up DNS (domain name service), which we won’t cover in this
tutorial.
You don’t need to set SECRET_KEY_BASE, even though it is in your con-
fig/secrets.yml file. Heroku sets it automatically.
Check that the environment variables are set with:
$ heroku config
See the Heroku documentation on Configuration and Config Vars and the article
Rails Environment Variables for more information.
Push to Heroku
After all this preparation, you can finally push your application to Heroku.
Be sure to commit any recent changes to the Git local repository before you
push to Heroku.
You commit your code to Heroku just like you push your code to GitHub.
Here’s how to push to Heroku:
You may see a message, “The authenticity of host ‘heroku.com’ can’t be es-
tablished. Are you sure you want to continue connecting (yes/no)?”. You can
answer “yes” and safely continue.
The push to Heroku takes several minutes. You’ll see a sequence of diagnostic
messages in the console, beginning with:
UPDATING THE APPLICATION 313
Counting objects...
$ git add -A
$ git commit -m "revised application"
$ git push
$ git push heroku master
$ heroku open
www.dbooks.org
314 CHAPTER 22. DEPLOY
If you’ve configured everything correctly, you should be able to sign up for the
newsletter and send a contact request.
Customizing
For a real application, you’ll likely want to use your own domain name for your
app.
See Heroku’s article about custom domains for instructions.
You may also want to improve website responsiveness by adding page caching
with a content delivery network such as CloudFlare. CloudFlare can also pro-
vide an SSL connection for secure connections between the browser and server.
Heroku offers many add-on services. These are particularly noteworthy:
For an in-depth look at your options, see the Rails Heroku Tutorial.
Troubleshooting
When you get errors, troubleshoot by reviewing the log files:
$ heroku logs
If necessary, use the Unix tail flag to monitor your log files. Open a new
terminal window and enter:
WHERE TO GET HELP 315
$ heroku logs -t
www.dbooks.org
316 CHAPTER 22. DEPLOY
Chapter 23
Analytics
In earlier chapters, we built the tutorial application and deployed it for hosting
on Heroku.
We’ve left something out. Though not obvious, it’s very important: analytics.
Analytics services provide reports about website traffic and usage.
You’ll use the data to increase visits and improve your site. Analytics close
the communication loop with your users; your website puts out a message and
analytics reports show how visitors respond.
Google Analytics is the best known tracking service. It is free, easy to use,
and familiar to most web developers. In this chapter we’ll integrate Google
Analytics with the tutorial application.
There are several ways to install Google Analytics for Rails. The article on
Analytics for Rails looks at various approaches and explains how Google Ana-
lytics works.
For this tutorial, we’ll use the Segment.com service. The service provides an
API to send analytics data to dozens of different services, including Google
Analytics.
317
www.dbooks.org
318 CHAPTER 23. ANALYTICS
Segment.com
Segment.com is a subscription service that gathers analytics data from your ap-
plication and sends it to dozens of different services, including Google Analyt-
ics. The service is free for low-volume websites, accommodating 1000 tracked
users per month at no cost. There is no charge to sign up for the service.
Using Segment.com means you install one JavaScript library and get access
to reports from dozens of analytics services. You can see a list of supported
services. The company offers helpful advice about which analytics tools to
choose from. For low-volume sites, many of the analytics services are free, so
Segment.com makes it easy to experiment and learn about the available ana-
lytics tools. The service is fast and reliable, so there’s no downside to trying
it.
(function(){
www.dbooks.org
320 CHAPTER 23. ANALYTICS
+ 'cdn.segment.com/analytics.js/v1/'
+ key + '/analytics.min.js';
})();
You can get the newest version of the code from the Segment.com Quick-
start page. If you copy a newer version of the code, remove the <script
type="text/javascript"> and </script> tags from the top and bottom.
The Rails asset pipeline will add the code to the application.js file which al-
ready contains the necessary <script> tags.
If you copy the code from the Segment.com Quickstart instructions, also re-
move:
www.dbooks.org
322 CHAPTER 23. ANALYTICS
Now you must add extra code to the Segment.com JavaScript snippet. The
extra code accommodates Turbolinks, plus page view and event tracking, which
we’ll look at next.
// accommodate Turbolinks
// track page views and form submissions
$(document).on('turbolinks:load', function() {
console.log('page loaded');
analytics.page();
analytics.trackForm($('#new_visitor'), 'Signed Up');
analytics.trackForm($('#new_contact'), 'Contact Request');
})
Add it after the last line. Add it after the orthographic car wreck that looks like
})();.
I’ll explain the purpose of this code next.
PAGE VIEW TRACKING WITH TURBOLINKS 323
To make sure every page is tracked when Rails Turbolinks is used, we’ve added
the following JavaScript to the app/assets/javascripts/segment.js file:
// accommodate Turbolinks
// track page views and form submissions
$(document).on('turbolinks:load', function() {
.
.
.
analytics.page();
.
.
.
})
Rails 4.0 introduced a feature named Turbolinks to increase the perceived speed
of a website.
Turbolinks makes an application appear faster by only updating the body and
the title of a page when a link is followed. By not reloading the full page,
Turbolinks reduces browser rendering time and trips to the server.
With Turbolinks, the user follows a link and sees a new page but Segment.com
or Google Analytics thinks the page hasn’t changed because a new page has not
been loaded. To resolve the issue, you could disable Turbolinks by removing
the turbolinks gem from the Gemfile. However, it’s nice to have both the speed
of Turbolinks and tracking data, so I’ll show you how to get tracking data with
Turbolinks.
Turbolinks fires a load event when a page has been replaced. The code listens
for the load event and calls the Segment.com analytics.page() method.
This code will work even on pages that are not visited through Turbolinks (for
example, the first page visited).
www.dbooks.org
324 CHAPTER 23. ANALYTICS
Event Tracking
Segment.com gives us a convenient method to track page views. Page view
tracking gives us data about our website traffic, showing visits to the site and
information about our visitors.
It’s also important to learn about a visitor’s activity on the site. Site usage data
helps us improve the site and determine whether we are meeting our business
goals. This requires tracking events as well as page views.
The Segment.com JavaScript library gives us two methods to track events:
• trackLink
• trackForm
// accommodate Turbolinks
// track page views and form submissions
$(document).on('turbolinks:load', function() {
console.log('page loaded');
analytics.page();
analytics.trackForm($('#new_visitor'), 'Signed Up');
analytics.trackForm($('#new_contact'), 'Contact Request');
})
The trackForm method takes two parameters, the ID attribute of a form and
a name given to the event.
Form tracking will show us how many visitors sign up for the newsletter or
submit the contact request form. Obviously we can count the number of sub-
scribers in MailChimp or look in the site owner’s inbox to see how many con-
tact requests we’ve received. But form tracking helps us directly correlate the
data with visitor data. For example, we can analyze our site usage data and see
which traffic sources result in the most newsletter sign-ups.
You can read more about the Segment.com JavaScript library in the Segment.com
documentation.
Troubleshooting
Click “Debugger” in the navigation bar so you can monitor data sent to Seg-
ment.com from your application.
When you test the application locally, you should see the results of page visits
and form submissions within seconds in the Segment.com debugger.
If you don’t see your page visits in the Segment.com debugger, open the browser
JavaScript console, visit a page, and check for the message “page loaded” in the
JavaScript console. In the Chrome browser, the JavaScript console is available
under the item “Developer” in the “View” menu.
Segment.com Integrations
After installing the Segment.com JavaScript snippet in your application, go to
your “sources” page and click the “integrations” link to visit the integrations
page to select the services that will receive your data.
Each service requires a different configuration information. At a minimum,
you’ll have to provide an account identifier or API key that you obtained when
www.dbooks.org
326 CHAPTER 23. ANALYTICS
Deploy
Commit to the Git repo and deploy to Heroku:
$ git add -A
$ git commit -m "analytics"
$ git push
When you visit the site, you should see real-time tracking of data sent to Seg-
ment.com in the Segment.com debugger.
Log into your Google Analytics account to see real-time tracking of visits to
your website. Under “Standard Reports” see “Real-Time Overview.” You’ll
see data within seconds after visiting any page.
IMPROVING THE USER EXPERIENCE 327
Conversion Tracking
You may only be interested in knowing that people visit your site, without
measuring visitors’ engagement or response to the site. But in most cases, if
you build a website, you’ll offer a way for visitors to respond, whether it is by
purchasing a product, signing up for a newsletter, or clicking a “like” button.
The ultimate measure of website effectiveness is the conversion rate. The term
comes from the direct marketing industry and originally referred to a measure
of how people responded to “junk mail” offers. For a website, the conversion
www.dbooks.org
328 CHAPTER 23. ANALYTICS
rate indicates the proportion of visitors who respond to a call to action, which
may be an offer to make a purchase, register for a membership, sign up for a
newsletter, or any other activity which shows the visitor is engaged and inter-
ested.
For our tutorial application, we can measure our website effectiveness by look-
ing at the conversion rate for newsletter sign-ups.
We’re tracking page views which will give us a count of visits to the website
home page. And we’ve got event tracking in place to count newsletter sign-ups.
If 100 people visit the home page and 10 people request a newsletter, we’ve got
a conversion rate of 10%.
We can try to improve the conversion rate by improving the user experience
(perhaps through A/B testing) or focusing on increasing traffic from sources
that provide a higher conversion rate.
You can monitor your site’s conversion rate by setting up events as goals in
Google Analytics. Segment.com also integrates with many services which pro-
vide conversion tracking.
understood his goals and the degree to which you’ve met his expectations. If
you’re working for yourself, or launching your startup, you may be your own
toughest boss, because there is always more to do.
With technology projects, like many other aspects of life, though it seems you’ll
never get it right, and never get it done, there are moments when you can savor
a sense of accomplishment. This is one of those moments.
Before you start thinking about adding one more feature, or updating the appli-
cation for the new releases that inevitably came out during the time you were
working, take time to bask in the satisfaction of seeing the results of your work.
Software development has its own unique rhythm of frustration and satisfac-
tion. As software developers, we subject ourselves to hours, days, or weeks of
struggle with code that is cryptic and resists understanding. We gain mastery
for a few minutes and then turn to the next problem. With each feature you im-
plement, or issue you resolve, you’ll experience brief elation before resuming
the grind of development. But at each milestone, and at the completion of the
project, you’ve built something tangible that you can use. You can try it out
yourself and show it to others.
Give yourself full credit. You’ve built something extraordinary with little more
than intelligence and attention. You’ve leveraged the work of other developers
who have contributed to the open source Ruby on Rails platform and you’ve
created your own unique product. This is what drives us as developers; to create
something from nothing, using only our collective intelligence and ambition.
www.dbooks.org
330 CHAPTER 23. ANALYTICS
Chapter 24
Testing
You don’t need to read this chapter if you will always be a student, or a hobby-
ist, working on personal projects. But if you wish to work as a professional
Rails developer, or launch your own startup, with money and reputation at
stake, you must learn about testing. In this chapter, I’ll introduce the basic
concepts of testing and show how to build a test suite for the tutorial applica-
tion.
Why Test?
Software applications are fragile. When you write a song, you can include a
wrong note and the song won’t break. In a film, technical flaws like a “jump
cut” or a microphone in the frame won’t ruin an entire movie. But an unseen
error in a software program can disrupt a key feature or crash the entire appli-
cation.
Software applications are never finished. Songs and movies reach a stage of
completion and are delivered to their audience, with no expectation that the
completed work will change. With software applications, there’s always an
upcoming version with bug fixes or new features. As web developers, we con-
tinue to make changes to the applications that our customers are actively using.
331
www.dbooks.org
332 CHAPTER 24. TESTING
for the methods of your tests, either Minitest or RSpec. Test code is different
from code that implements features in one significant way: Instead of support-
ing interactions with a user, test code interacts with the code you’ve written,
verifying the code behaves as intended.
Scripted or Exploratory
When testing is used for quality assurance, the goal is to create a suite of auto-
mated tests that will reveal any bugs that creep into code and break the applica-
tion. Sometimes this is called scripted testing. These tests are checked into the
software repository and maintained with the application. Often developers will
set up a system for continuous integration (CI), which will automatically run
the test suite whenever the repository is updated. Developers can set up a CI
server such as Jenkins or use a hosted CI service such as Travis CI, CircleCI,
or Semaphore to run tests automatically. Automated testing with continuous
integration serves as a safety net for developers.
There is another role for testing, which is often called exploratory testing, or
developer testing. These tests may end up in an application test suite, but the
primary purpose is to help a developer construct an application. Many devel-
opers, after gaining experience in writing tests for quality assurance, realize
that writing tests can be a useful first step in figuring out how a feature should
be implemented. It may seem odd to write tests first, but exploratory test-
ing can clarify what behavior will be required, and help the developer think
through alternatives and edge cases. This approach is called test-first develop-
ment, and many developers will tell you that when you write tests first, you’ll
be more satisfied; you’ll be more focused; and you’ll avoid tangents and de-
tours of the “nice-to-have-but-not-really-needed” variety. We’ll look closely
at test-first development in conjunction with Test-Driven Development (TDD)
and Behavior-Driven Development (BDD) at the end of this chapter. First, let’s
gain an understanding of testing terminology and practice.
www.dbooks.org
334 CHAPTER 24. TESTING
well, a small section of the code, such as a class or a method, will be a discrete
unit that can be tested independently of all other units. Unit tests inspect the
integrity of small parts of the application in isolation. When a unit test fails,
we can quickly identify and fix broken code.
We use integration tests to make sure the entire application works as expected.
Integration tests mimic the behavior of real users. For a web application, an in-
tegration test may simulate a user signing in, filling out forms, clicking between
pages, and verifying that contents of pages match expected results. Integration
tests can also be called feature tests if they are designed to confirm that product
features work as expected. Our feature tests can serve as acceptance tests if we
use the test suite to determine if we’ve correctly implemented our user stories
or other product specifications. Sometimes these tests are called black box tests
because the code is tested as if the application was a black box, with the inter-
nal workings of the application hidden from the observer. They are also called
system tests or end-to-end tests.
Sample Data
When we write tests, either feature tests or unit tests, we often want to check
whether a method returns the data we expect. That means we have to create
the data we need in advance of the test. Either we populate a database with
the data we expect, or we disconnect the database and instantiate an object
that provides the data we expect. Test frameworks give us a tool named a
factory or a fixture to create sample data. Developers argue about what is better,
factories or fixtures, but you’ll encounter factories more often, particularly the
popular FactoryGirl gem. A factory is an object that creates other objects.
When you use FactoryGirl, you have the option of saving your object to the
database (which is slow) or building your object in memory only (which is
faster). Fixtures are used to populate a database with sample data before your
tests run. If you use fixtures, you’ll save sample data in a configuration file.
Before tests run, Rails automatically loads all fixtures from configuration files
in the test/fixtures folder. As you gain experience with testing, you’ll become
www.dbooks.org
336 CHAPTER 24. TESTING
Test Doubles
In unit testing, to isolate small parts of the application, sometimes we artifi-
cially decouple the code from the rest of the application. For example, with a
unit test, we don’t want to connect to an external service with an API to obtain
data. Or we simply want a method to get a predictable response from another
object.
Test doubles stand in for external dependencies. The term is borrowed from
Hollywood, where stunt doubles stand in for actors in action scenes. A test
double is any kind of pretend object used in place of a real object for testing
purposes. There are two types of test doubles, stubs and mocks. Stubs provide
canned answers to calls made during the test, only responding when queried
by the test. Sometimes stubs record information about the call, for example,
the message sent or the number of times called. Mocks are pre-programmed
objects that reproduce the behavior of the object they represent, forming a spec-
ification of an object’s behavior. It takes time to write stubs and mocks and lots
of experience to use them correctly, so as a beginner, you probably won’t write
stubs and mocks without help. As you can gain experience, you’ll better un-
derstand the difference between stubs and mocks and learn how to use them.
For now, it is enough to recognize the terminology and remember that tests run
faster and better when we reduce coupling and complexity with test doubles.
release of Ruby 1.9, Minitest has been supplied as a standard gem with all
Ruby installations. Yet most Rails developers use RSpec for testing.
In this tutorial, I’ll use Minitest to introduce you to testing. Minitest is easier
to set up and offers a syntax that is very similar to RSpec. Some developers
say that there is no reason to use RSpec because Minitest provides almost all
the convenience of RSpec with smaller size, faster speed, and less complexity.
Other developers insist that RSpec is more expressive and flexible. Realis-
tically, if you want a job working on most Rails teams, you’ll need to learn
RSpec. Get started with Minitest to learn the basics of testing. When you’re
ready for the next step, the Capstone Rails Tutorials will take you deeper. I also
recommend the books Rails 4 Test Prescriptions by Noel Rappin and Everyday
Rails Testing with RSpec by Aaron Sumner.
www.dbooks.org
338 CHAPTER 24. TESTING
• set up
• visit page
• neutralize
The setup phase may include creating a user, signing in, or any other activity
that creates the conditions for a test. With Capybara, the test visits the page,
which requires Capybara to simulate a browser request to the Rails application.
FOUR PHASES OF UNIT TESTS 339
Then, in the third stage, we check if the server response contains the data we
expect. Finally, we may need to clean up, resetting the original state of the
application, or removing any data the test added to the database.
• set up
• exercise
• verify
• teardown
When you test a small part of the application in isolation, you’ll focus on an
object or method which we call the “system under test.” The setup phase pre-
pares the system under test. Often this means instantiating an object. Here is
an example:
During the exercise phase, something is executed. Often this is a method call:
user.save
During verification, the result of the exercise is verified against the developer’s
expectations:
www.dbooks.org
340 CHAPTER 24. TESTING
user.email.must_equal '[email protected]'
During teardown, the system under test is reset to its initial state. Rails inte-
grates with Minitest or RSpec to reset a database to its initial state. You will
seldom write code for the teardown phase.
Now that you’ve learned about the basic concepts of testing, let’s set up Minitest
for our first tests.
Set Up Minitest
We’ll set up testing with both Minitest and Capybara, so we can write both
unit tests and feature tests. Minitest is a standard Ruby gem, installed when
you install Ruby in your environment. We’ll install the minitest-spec-rails gem
which makes it easy to use an RSpec-like syntax with Minitest. We’ll also add
the minitest-rails-capybara gem to integrate Capybara with Minitest and Rails.
Open your Gemfile and replace the contents with the following:
Gemfile
source 'https://rubygems.org'
ruby '2.4.1'
gem 'rails', '~> 5.1.2'
# Rails defaults
gem 'sqlite3'
gem 'puma', '~> 3.7'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
group :development, :test do
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
gem 'capybara', '~> 2.13'
gem 'selenium-webdriver'
end
group :development do
SET UP MINITEST 341
# learn-rails
gem 'bootstrap-sass'
gem 'gibbon'
gem 'high_voltage'
gem 'jquery-rails'
group :development do
gem 'better_errors'
gem 'rails_layout'
gem 'sqlite3'
end
group :production do
gem 'pg'
end
group :test do
gem 'minitest-spec-rails'
gem 'minitest-rails-capybara'
end
We’ve added the two gems to the test group. Now, some gems are loaded
only when we’re writing code (during development), some are loaded only
when the application is running on Heroku (deployed to production), and our
newest additions only are loaded when we run tests.
Next, install the additional gems:
$ bundle install
The bundle install command will download and install the gems from the
rubygems.org server.
Run Tests
The command rails test will execute Minitest. Let’s see what happens
when we run tests:
www.dbooks.org
342 CHAPTER 24. TESTING
$ rails test
Running via Spring preloader in process 29254
/Users/danielkehoe/workspace/learn-rails/db/schema.rb doesn't exist yet.
Run `rails db:migrate` to create it, then try again. If you do not intend
to use a database, you should instead alter /Users/danielkehoe/workspace/
/learn-rails/config/application.rb to limit the frameworks that will be loaded.
Run options: --seed 35136
# Running:
Finished in 0.005570s, 0.0000 runs/s, 0.0000 assertions/s.
0 runs, 0 assertions, 0 failures, 0 errors, 0 skips
Rails Minitest informs us that our application is not set up to use a database.
The easiest way to resolve the issue is to run rails db:migrate which sets
up the database schema file. We’re not using a database for this application so
the database schema file will be empty.
$ rails db:migrate
The rails db:migrate command doesn’t produce any result in the terminal
but it will create a new db/schema.rb file.
Try running rails test again:
$ rails test
Running via Spring preloader in process 29468
Run options: --seed 46952
# Running:
The output shows that Minitest executes but we have no tests for it to run.
Let’s commit our changes to the Git repository and push to GitHub:
UNIT TEST (STANDARD SYNTAX) 343
$ git add -A
$ git commit -m "set up minitest"
$ git push
require 'test_helper'
def valid_params
{ email: '[email protected]' }
end
def test_valid
visitor = Visitor.new valid_params
assert visitor.valid?, "Can't create with valid params: #{visitor.errors.messages}"
end
def test_invalid_without_email
params = valid_params.clone
params.delete :email
visitor = Visitor.new params
refute visitor.valid?, "Can't be valid without email"
assert visitor.errors[:email], "Missing error when without email"
end
end
Notice that we must declare a class VisitorTest that inherits from ActiveSupport::Te
Then we must define a new method for each test case using the def keyword.
This syntax is not popular with Rails developers. RSpec offers its own DSL
(domain specific language) that hides the overhead of setting up classes and
methods behind convenience methods. Minitest offers its own version of the
www.dbooks.org
344 CHAPTER 24. TESTING
the RSpec DSL, allowing us to use the more popular syntax. I’ll use the new
RSpec-like syntax in this tutorial, since you are likely to encounter RSpec more
frequently.
require 'test_helper'
describe Visitor do
end
The test above, written in the RSpec-like syntax, is functionally identical to the
previous example, written in the old test_unit syntax. Take a close look at both,
so the structure and keywords will be familiar when you see it again.
UNIT TEST (SPEC SYNTAX) 345
describe Visitor do
.
.
.
end
The describe keyword creates a test class. In this case, the describe key-
word will create a class named VisitorTest that inherits from ActiveSupport::TestCa
Using the old test_unit syntax, we could do this with class VisitorTest
< ActiveSupport::TestCase but the describe keyword is more conve-
nient. When Minitest runs, it recognizes and executes test classes. By including
our code inside a test class, we get to use methods such as let and it which
are useful for writing tests. Minitest will recognize various classes like models
or controllers and provide appropriate behavior.
Setup Phase
We must set up everything we need for the test. Minitest provides a simple way
to set up everything before a test using the before keyword:
www.dbooks.org
346 CHAPTER 24. TESTING
before do
do_some_setup
end
We could initialize the Visitor model using a before block and setting instance
variables:
before do
@visitor_params = {email: '[email protected]'}
@visitor = Visitor.new(visitor_params)
end
Instead of using a before block, we’ll use the convenient let keyword:
Do It
Each test is defined by the it keyword and a do ... end block that contains
the exercise and verify phases of the test. The it keyword must be accompa-
nied by a description. The description will be displayed if the test fails.
For our first test, we want to check if the Visitor model can be created when we
provide a valid email address. Before the test runs, the let statement makes
sure the Visitor object is instantiated with an email value.
The verification phase of each test consists of a comparison between the results
of an operation and our expectations. We expect that each time we create a
UNIT TEST (SPEC SYNTAX) 347
Visitor object with a valid email address, the visitor.valid? method will
return true. We can create a test:
The keyword assert_equal is the old test_unit syntax. It compares the result
of visitor.valid? with true and tells Minitest the test has passed or failed.
We can write the same thing using the new RSpec-style syntax:
The method must_be is an expectation. You can see a Minitest cheat sheet
with a list of all the expectation methods. As you might guess, must_be func-
tions as a comparison operator, checking if a call to visitor.valid? returns
true.
For our second test, we want to make sure the Visitor object is invalid when no
email address is provided:
www.dbooks.org
348 CHAPTER 24. TESTING
Run Tests
Let’s run our unit tests:
$ rails test
Running via Spring preloader in process 29585
Run options: --seed 7800
# Running:
..
Let’s see what happens if we purposefully break our Visitor model. Modify the
file app/models/visitor.rb:
RUN TESTS 349
class Visitor
include ActiveModel::Model
attr_accessor :email
# validates_presence_of :email
# validates_format_of :email, with: /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i
def subscribe
mailchimp = Gibbon::Request.new(api_key: Rails.application.secrets.mailchimp_api_key)
list_id = Rails.application.secrets.mailchimp_list_id
result = mailchimp.lists(list_id).members.create(
body: {
email_address: self.email,
status: 'subscribed'
})
Rails.logger.info("Subscribed #{self.email} to MailChimp") if result
end
end
When you copy this, be careful to keep the long regex expression (/\A. . . \z/i)
on one line (no line breaks).
We’ve commented out the statements that require validation for the email at-
tribute. Let’s run the tests again:
$ rails test
Running via Spring preloader in process 29655
Run options: --seed 45089
# Running:
Failure:
Visitor#test_0002_is invalid without an email
[/Users/danielkehoe/workspace//learn-rails/test/models/visitor_test.rb:15]:
Expected #<Visitor:0x007fa5440a2260 @validation_context=nil,
@errors=#<ActiveModel::Errors:0x007fa5440a1f40 @base=#<Visitor:0x007fa5440a2260 ...>,
@messages={}, @details={}>> to not be valid?.
www.dbooks.org
350 CHAPTER 24. TESTING
The output shows a failure. The diagnostic message displays the description of
the failing test, “Visitor#test_0002_is invalid without an email”, and indicates
the line number where the test failed. Now you know what a failing test looks
like.
Before you continue, restore the file app/models/visitor.rb to its original state,
and make sure the tests pass.
If you wish, you can continue writing unit tests. You could create a similar
unit test for the Contact model. With more experience, or some independent
research, you could create a test for the subscribe method in the Visitor
model. This method connects to an external API, so it requires test doubles to
fake the response of the external services. Our goal here is to introduce you to
the concepts of testing, so we’ll put aside advanced work on unit tests, and take
a look at feature tests.
Feature Test
Let’s start with a user story for our home page. It might seem trivial to call
the home page a “feature” and describe it with a user story, but it illustrates a
process that works just as well with more complex features. Here’s our user
story:
For our test, we know we want to visit the home page and check if the words
“Stay in touch” appear on the page. This is the scenario we’ll test:
require 'test_helper'
I’ve included the user story and scenario description in comments. There’s no
convention to do so, but it will help you to see the relationship between testing
and the product planning process. It should be easy to transform a “Given. . .
When. . . Then. . . ” scenario into the code needed for a feature test.
Feature
When we created a unit test, we used the describe keyword to create a
test class. The feature keyword creates a test class that inherits from the
www.dbooks.org
352 CHAPTER 24. TESTING
Notice that the description is placed in quotes. In this case, Minitest will auto-
matically generate a class named HomePageTest.
Scenario
Typically we test a single feature with multiple scenarios in a single test file.
The scenario keyword is similar to the it keyword you’ve seen in unit tests.
Each feature test is defined by the scenario keyword and a do ... end
block that contains the visit and verify phases of the test. The scenario key-
word must be accompanied by a description. The description will be displayed
if the test fails.
The directive visit is a Capybara method that takes a URL or Rails route as
an argument. You could specify either visit ’/’ or visit root_path to
direct Capybara to retrieve the home page.
Capybara provides other actions in addition to visit. You can see the doc-
umentation for Capybara actions that include actions for filling in a form and
clicking a button.
RUN TESTS 353
Capybara creates a page object for us as a response to the visit. The page
object is a representation of the HTML file returned by the application. We can
call the must_have_content method, testing if the string “Stay in touch” is
present in the page.
Capybara gives us a collection of methods we can use to verify our expec-
tations. The documentation for Capybara expectations provides an extensive
collection of methods we can use to verify what’s on a web page. For example,
must_have_link checks for a link. With Capybara expectations, you can
check almost anything on a page. Combining Capybara actions and expecta-
tions allows you to build a powerful page-checking robot.
Run Tests
Let’s run all our tests:
$ rails test
Running via Spring preloader in process 30144
Run options: --seed 51858
# Running:
...
We have three tests (in two test files) making four assertions, all passing.
Troubleshooting
www.dbooks.org
354 CHAPTER 24. TESTING
rails aborted!
NoMethodError: undefined method `feature' for main:Object
You’ll see this error message if you neglected to modify the test/test_helper.rb
file to allow use of the Capybara test framework methods.
We’ve changed the welcome message from “Stay in touch” to “GO AWAY!”.
Let’s run the tests again:
$ rails test
Running via Spring preloader in process 30059
Run options: --seed 39958
RUN TESTS 355
# Running:
Failure:
Home page Feature Test#test_0001_visit the home page
[/Users/danielkehoe/workspace//learn-rails/test/integration/home_page_test.rb:15]:
Expected to find text "Stay in touch" in "Toggle navigation Home About Contact GO AWAY!".
..
The output shows a failure. The diagnostic message displays the description
of the failing test, “Home page Feature Test#test_0001_visit the home page”,
showing a failure, “Expected to include ‘Stay in touch’.”
Before you continue, restore the file app/view/visitors/new.html.erb to its
original state, and make sure the tests pass.
Now that we have written a few basic tests, let’s commit our changes to the Git
repository and push to GitHub:
$ git add -A
$ git commit -m "add tests"
$ git push
Using Capybara
There is an art to developing feature tests. You can test that all the text on
the home page is exactly what you want. That would make your test files
large. And your tests would be “brittle,” because any changes you made in
www.dbooks.org
356 CHAPTER 24. TESTING
development, even the slightest changes to the words on the page, would break
your tests. For good integration tests, focus on the features that are essential to
your application. For example, use the Capybara robot to make sure the user
can follow a critical path through your application, visiting important pages,
filling in forms, clicking buttons, and seeing results. Capybara lets you select
any HTML element on a page, so you can check an ID or class attribute of an
HTML tag, not just text on a page. You’ll want to be confident that application
navigation and page flow continues to work after any code changes. That will
serve you better than tests that tell you a word changed here or there.
Other Tests
The art of testing lies in making good choices about what to test. It’s com-
mon to write feature tests because they will test the entire application from the
viewpoint of the user. It is also common to write unit tests for models because
models contain much of the uniqueness of an application.
Every other aspect of a Rails application can be tested, including controllers,
helpers, and views. Developers seldom write tests for every aspect of a Rails
application. If your controllers contain only the standard RESTful actions, with
no extra logic, you probably don’t need to write unit tests for your controllers.
If you only have simple HTML markup in helpers, helpers don’t need to be
tested. And views are rarely tested with unit tests (use feature tests if you want
to make sure a page contains what you expect). As a beginner, you’ll make a
good start if you concentrate on unit tests for models and integration tests for
your page flow.
Behavior-Driven Development
In Book One, you learned about the software development approach called
Behavior-Driven Development (BDD), or sometimes, Behavior-Driven Design.
TEST-DRIVEN DEVELOPMENT 357
In writing the feature tests for the home page, you saw it in action. With BDD,
you turn user stories into detailed scenarios that are accompanied by tests. BDD
is a powerful approach for managing software development. It helps you define
your product requirements, refine your project scope, and divide your project
into well-defined tasks. The BDD process is complete when each feature has
automated tests, when you enter rails test on the command line and see
that every feature is implemented and functioning as expected.
You may feel lost or overwhelmed when you attempt to build a Rails applica-
tion for the first time, especially if your only experience is following the step-
by-step instructions of a tutorial. When you experience that panic, BDD is your
lifeline. Start by writing user stories for a few simple features. Write feature
tests and implement the code required to make the tests pass. As you focus on
the process of writing scenarios and tests, and implementing the code for each
feature, you’ll begin to gain momentum, and before you know it, you’ll be over
the first hurdle.
Test-Driven Development
You can see how the BDD approach refines the product requirements and user
experience. At a microscopic level, a similar discipline, named test-driven
development, helps refine the implementation. Where BDD is driven by feature
tests, TDD is focused on unit tests.
TDD is an approach to software development that emphasizes that all code
should be written to be tested. Excellent test coverage, allowing easy refactor-
ing, is not the only goal of TDD. Just as important, the developer focuses on
what needs to be accomplished and thinks through alternatives and edge cases.
Some TDD aficionados say testing is a tool to write better code, and regression
tests are a side effect. Unit tests are at the heart of TDD, and easiest to write
when code is carefully decoupled into systems that can be tested in isolation.
An application that is composed of decoupled units with clearly defined inter-
faces is a well-designed application that is easy to extend and maintain. If you
www.dbooks.org
358 CHAPTER 24. TESTING
make it a practice to write unit tests in conjunction with all the code you write,
you’ll write better code, and you’ll be practicing TDD.
Test-First Development
Often when you are practicing TDD, you’ll write tests before you write imple-
mentation code. Earlier in this chapter, I referred to test-first development and
explained that it serves a different purpose than testing for quality assurance. In
some situations, test-first development is simply exploratory testing, a means
of describing the behavior of the code that must be built. Test-first develop-
ment is particularly useful when you’ve solved a similar problem and know
exactly what results to expect, making it easy to write tests before writing the
implementation.
Test-first development leads to a “red-green-refactor” workflow. A developer
imagines the results of an operation, writes a test that checks for the results, and
runs tests which fail (with the right configuration, failing tests display as red in
the console). Then the developer writes code that produces the correct results
and runs the tests again, improving the code until the tests pass (displaying
in green). At this point, the developer has an adequate regression test and
can begin to refactor to improve the implementation, checking that the tests
continue to pass. Developers like the rhythm and coherency of the “red-green-
refactor” workflow. Writing tests creates discrete, manageable tasks. When
tests pass, turning green, there is a feeling of satisfaction, of a job well-done.
By postponing concerns about improving the code to a refactoring phase, it’s
easier to get the job done without trying to get it perfect. And perfection can be
pursued in the refactoring phase without worrying about regressing to a broken
state.
David Heinemeier Hansson, the creator of Rails, famously declared that TDD
is dead. Long live testing.. He pointed out that sometimes ardent advocates
of TDD will try out an implementation before writing tests, to determine what
needs to be done, or to clarify a problem. In the real world, even though de-
WORDS OF ENCOURAGEMENT 359
velopers recommend writing tests first, there are often times when a developer
will write tests only after writing code and settling on an approach. TDD,
which emphasizes the benefit of writing tests as a first step, doesn’t really re-
quire that you write tests before you write code, or even that you write tests
for all code. The test-first emphasis of TDD is a recommendation, not a rule.
You’ll be a better developer if you find opportunities to get “in the zone” with
the red-green-refactor workflow of test-first development, but testing is worth-
while whether it comes first or last.
Words of Encouragement
Testing often intimidates the newcomer. It is difficult to find good examples.
The syntax of Minitest and RSpec has evolved over time, so there is little con-
sistency among examples you’ll find. Older examples are not a good guide
to current practices. But once you gain familiarity with the concepts in this
chapter, you can start writing tests.
Testing is one of the few things in Rails that you can jump into without getting
just right. You can’t screw up your code base by writing incorrect tests. Ex-
perienced developers seem to worry that inexperienced developers will write
slow tests, but in truth, a slow test is better than no test. Tests won’t affect the
performance of your application in production.
If your code is clumsy, don’t worry, you’ll get better with practice. What’s
most important is that you’ve begun writing tests. That’s an indication you are
committed to Rails best practices.
Your tests are only “bad” if they don’t cover your code adequately or if they
give you a false sense of assurance. You will only discover this over time, as
you find bugs you didn’t anticipate (which is inevitable). It’s better to just begin
testing, even if you’re not sure you’re doing it right, than to not test at all.
www.dbooks.org
360 CHAPTER 24. TESTING
Chapter 25
Rails Composer
I’m going to show you how to skip all the work you already did, and build
a ready-to-use Rails application in less than five minutes. When you’re done
with this chapter, you may wonder why you read the rest of the book.
Watch the video for a demonstration of Rails Composer:
• Rails Composer
361
www.dbooks.org
362 CHAPTER 25. RAILS COMPOSER
ponents, it makes sense to rely on an open source effort to stitch them together,
so any integration issues or update problems are quickly resolved by the com-
munity. That’s the idea behind the RailsApps project. The project provides a
collection of starter applications, plus Rails Composer, a tool that creates the
starter applications.
I’ve been leading the RailsApps project for several years because I think the
project saves time for developers and makes things easier. I may be biased, so
take a look and judge for yourself.
$ cd ../
$ pwd
/Users/danielkehoe/workspace
$ cd ~/workspace
$ pwd
/Users/danielkehoe/workspace
Options #2 and #3 are not for beginners. We’ll skip any contributed applica-
tions. And the “Custom application” option is strictly for experts. Enter 1 to
select “Build a RailsApps example application.” You’ll see a list of available
starter applications:
We’ll explore the list later. For now, enter 1 to select “learn-rails”.
www.dbooks.org
364 CHAPTER 25. RAILS COMPOSER
Here’s your chance to get news and announcements about Rails Composer:
Enter your email address (if you want news) or press “return” to skip it (if
you’re shy).
In less than the time it took me to write a few sentences, you’ll have a new
Rails application. Look for it in your folder:
$ ls -1
foobar-kadigan
learn-rails
$ cd foobar-kadigan
As soon as you move into the foobar-kadigan/ folder, RVM will automati-
cally begin using the gemset named “foobar-kadigan.” That’s because Rails
Composer created hidden .ruby-gemset and .ruby-version files.
Run bundle install to install the necessary gems in the RVM gemset:
BUILD ‘LEARN RAILS’ IN LESS THAN FIVE MINUTES 365
$ bundle install
$ cd foobar-kadigan
$ rails server
=> Booting Puma
.
.
.
www.dbooks.org
366 CHAPTER 25. RAILS COMPOSER
Rails Bootstrap
Rails Foundation
Rails 4.2 added the Active Job feature for background processing. The Mail-
ing List with Active Job tutorial explains how to use it. You can use Rails
Composer to generate the rails-mailinglist-activejob starter application.
In the “Send Mail” chapter I wrote about “Asynchronous Mailing” which pro-
vides a queueing system for background jobs. For a production website, it is
smart to use Active Job for better website performance for users. The Mailing
List with Active Job tutorial in the Capstone Rails Tutorials series explains the
code.
Rails OmniAuth
Rails Devise
Devise is the most popular gem for authentication. Devise provides user man-
agement and authentication, letting a user sign up to create an account and log
in with an email address and password. Most websites need email/password
authentication, so this is a popular starter application.
www.dbooks.org
368 CHAPTER 25. RAILS COMPOSER
You can examine the example application on GitHub, in the rails-devise repos-
itory.
You can read the Devise Quickstart Guide in the Capstone Rails Tutorials series
to learn about user management and authentication with Devise.
To keep controllers skinny, Rails developers often use the Pundit gem for au-
thorization. It improves upon simple role-based authorization to move access
control code from controllers to separate “policy objects.” For complex appli-
cations with elegant architecture, use the “rails-devise-pundit” starter applica-
tion.
You can examine the example application on GitHub, in the rails-devise-pundit
repository.
You can read the Pundit Quickstart Guide in the Capstone Rails Tutorials series
to learn about authorization with Pundit.
A COLLECTION OF STARTER APPLICATIONS 369
• rails-signup-download
• rails-stripe-checkout
• rails-stripe-coupons
www.dbooks.org
370 CHAPTER 25. RAILS COMPOSER
$ cd ~/workspace
$ pwd
/Users/danielkehoe/workspace
It’s okay to start with the “learn-rails” gemset. We have to start with a gemset
that already has the Rails gem installed. After that, Rails Composer will create
a new gemset for the new project.
Don’t worry if some of the prompts are different from the ones I describe here.
Rails Composer changes often. At the time I wrote this, I saw:
RAILS COMPOSER OPTIONS 371
Select “rails-devise-roles” (it was #7 when I wrote this, but the list may have
changed).
Another chance to get on the mailing list. Just hit “return” if you already signed
up.
www.dbooks.org
372 CHAPTER 25. RAILS COMPOSER
Our first option! We’ve always used Puma since it is the Rails default. Choose
“Puma” to keep things familiar.
We haven’t explored applications that use databases in this book, but Devise
and role-based authorization require saving a User model to a database. Choose
“SQLite,” which is built-in and ready to run in the Mac or Ubuntu environ-
ments. Developers prefer PostgreSQL for production applications, but it takes
extra effort to set up, so we’ll stick with SQLite for now.
In this book, all our view templates were written using the ERB template lan-
guage. In the “Concepts” chapter in Book One, you learned that components
of Rails can be mixed for different stacks. Some developers substitute Haml or
Slim for ERB. I’ve written an article on Haml and Rails if you’d like to know
more. Choose “ERB” for now.
RAILS COMPOSER OPTIONS 373
You learned to use Bootstrap 3 in this book. Let’s stick with that. Choose
“Bootstrap 3.3.”
Devise will need to send email for its “forgot password” feature. Configuring
email took some time for our tutorial application. Rails Composer will instantly
set up everything we need to send email using our choice of services. Choose
“SendGrid” for now.
www.dbooks.org
374 CHAPTER 25. RAILS COMPOSER
Choose “Devise with default modules.” Devise has options, like a Confirmable
module that requires users to click a link in an email message to confirm a new
account. The Invitable module provides a feature that allows administrators
or other users to invite users to establish accounts. We won’t need these extra
features.
We could add the SimpleForm gem to make it easy to build forms. We didn’t
use it in this book, so we’ll choose “none.”
Next you’ll see a menu of page layout options from Rails Composer. These are
available if you use Bootstrap 3.
5) 4 Col Portfolio
6) Bare
7) Blog Home
8) Business Casual
9) Business Frontpage
10) Clean Blog
11) Full Width Pics
12) Heroic Features
13) Landing Page
14) Modern Business
15) One Page Wonder
16) Portfolio Item
17) Round About
18) Shop Homepage
19) Shop Item
20) Simple Sidebar
21) Small Business
22) Stylish Portfolio
23) The Big Picture
24) Thumbnail Gallery
choose Enter your selection:
www.dbooks.org
376 CHAPTER 25. RAILS COMPOSER
You can enter your Segment.com Write Key here, if you know it. Otherwise,
hit return and you’ll get a placeholder you can replace later.
This option sets up your starter application for deployment to Heroku. Choose
“no” for now.
Some developers find Rails Turbolinks annoying when they wish to integrate
JavaScript with their Rails applications.
We’re not adding any JavaScript so choose “n” to use Rails Turbolinks.
In the “Deploy” chapter you learned that you can leave your website out of
Google search results with the robots.txt file. Let’s answer “y” or “yes” and
play it safe.
Rails Composer will create a GitHub repository for your starter application if
your credentials are set up correctly. Let’s play it safe and answer “n” or “no”
to skip the repository option.
TRY IT OUT 377
Rails Composer has all the answers it needs. On my computer, with a fast
Internet connection in the heart of San Francisco, Rails composer takes about
thirty seconds to build the starter application. It installs every needed gem;
sets configuration files; and generates views, models, controllers, and routes.
The developers who maintain the Rails Composer project have worked out any
tricky integration issues so you can expect the starter application to work with-
out any problems.
Try It Out
You’ve added a new application to your collection of projects:
$ ls -1
foobar-kadigan
learn-rails
rails-devise-roles
$ cd rails-devise-roles
$ git log --oneline
087167a rails_apps_composer: extras
6d4f710 rails_apps_composer: add Bootstrap page layouts
be68589 rails_apps_composer: navigation links
3126403 rails_apps_composer: set up database
53a029f rails_apps_composer: add README files
7c78031 rails_apps_composer: add analytics
99e9c0c rails_apps_composer: add pages
1886d2c rails_apps_composer: front-end framework
38242d7 rails_apps_composer: add roles to a User model
839749f rails_apps_composer: devise
62753db rails_apps_composer: set email accounts
0754893 rails_apps_composer: generators
09104b9 rails_apps_composer: Gemfile
b61cd18 rails_apps_composer: initial commit
Rails Composer set up a Git repository and committed files as it built the ap-
plication. We can see a list of Git commits with the git log -oneline
www.dbooks.org
378 CHAPTER 25. RAILS COMPOSER
command.
When you move into the rails-devise-roles/ folder, RVM will automatically
begin using the gemset named “rails-devise-roles” because of the hidden .ruby-
gemset and .ruby-version files.
Run bundle install to install the necessary gems in the RVM gemset:
$ bundle install
$ rails server
=> Booting Puma
.
.
.
www.dbooks.org
380 CHAPTER 25. RAILS COMPOSER
Composer.
To learn more about Rails Composer, see the Rails Composer home page and
the README for the Rails Composer project on GitHub.
Chapter 26
Version Notes
If you are reading the online edition of the book, you have the most recent
version of the book. If you’ve gotten your copy of the book elsewhere, you
may have an older version that doesn’t have the newest updates.
You’ll find the version number and release date on the first page of this book
(under the book title). Check the learn-rails GitHub repository to find out if
you have the newest version of the book. The README page on the GitHub
repo always shows the most recent version number for the book and the tutorial
application.
If you have trouble building the application in this book, and suspect something
may be out of date, you can check the Gemfile in the repo to see if we’ve
changed gems or specified version numbers to avoid compatibility issues. You
can also check the CHANGELOG, look at recent commits, and check the issues
to see the current state of the application.
Here are the changes I’ve made.
Version 4.2.0
Version 4.2.0 was released August 2, 2017
381
www.dbooks.org
382 CHAPTER 26. VERSION NOTES
Version 4.1.0
Version 4.1.0 was released July 3, 2017
Updated for Rails 5.1 and Ruby 2.4.1.
Removed SimpleForm and replaced with Rails 5.1 form_with.
No need to configure MiniTest for Capybara (included in Rails 5.1).
Version 4.0.2
Version 4.0.2 was released November 25, 2016
Minor revisions for clarity.
Apple now calls the operating system macOS not Mac OS X.
Updated for Ruby 2.3.2.
Version 4.0.1
Version 4.0.1 was released November 4, 2016
Fixed broken links.
Removed references to Nitrous.io because Nitrous.io is out of business.
VERSION 4.0.0 383
Version 4.0.0
Version 3.1.0
Version 3.0.2
Version 3.0.1
www.dbooks.org
384 CHAPTER 26. VERSION NOTES
Version 3.0.0
Version 3.0.0 was released January 14, 2016
Extensive revision throughout the book, and the length of the book increased,
so the book is now two books. Book One contains the introductory and self-
help chapters and can be read without access to a computer. Book Two contains
the step-by-step tutorial and requires use of a computer.
Switch to using the Mandrill service to send email. Previously used Gmail but
Google has taken steps to make Gmail more secure and now it can be difficult
to send email from a Rails application using Gmail.
Sending mail now requires the method deliver_now instead of deliver.
The UserMailer class now inherits from ApplicationMailer.
Updated references to Rails from version 4.2.4 to 4.2.5.
Updated references to Ruby from version 2.2.3 to 2.3.0.
Version 2.2.2
Version 2.2.2 was released October 30, 2015
In the “Front-End Framework” chapter, updated filename to 1st_load_framework.css.s
from framework_and_overrides.css.scss to reflect a change in the rails_layout
gem.
Version 2.2.1
Version 2.2.1 was released September 19, 2015
Updated references to Ruby from version 2.2.0 to 2.2.3.
Updated references to Rails from 4.2.0 to Rails 4.2.4.
VERSION 2.2.0 385
Updated Visitor model subscribe method for the new Gibbon 2.0 API.
Recommending Cloud9 instead of Nitrous.io because Nitrous.io is no longer
free.
Version 2.2.0
Version 2.2.0 was released June 6, 2015
For Amazon customers, added an offer to access the online version or download
a PDF at learn-rails.com.
Google now requires use of OAuth 2.0 for application access to Google Drive.
The implementation is considerably more complex than the previous imple-
mentation using a Gmail address and password. I’ve dropped the “Spreadsheet
Connection” chapter.
Minor clarification in the “Layout and Views” chapter.
Version 2.1.6
Version 2.1.6 was released March 17, 2015
Remove references to the Thin web server in the “Deploy” chapter.
Correct version number for gem ’sass-rails’ in various Gemfile listings.
Fixes issue 49 and an error “Sass::SyntaxError - Invalid CSS” when the Foun-
dation front-end framework is used.
In the “Testing” chapter, the file test/integration/home_page_test.rb was miss-
ing require ’test_helper’.
Updated “Rails Composer” chapter to describe new options.
Minor improvements and corrections of typos.
www.dbooks.org
386 CHAPTER 26. VERSION NOTES
Version 2.1.5
Version 2.1.5 was released March 4, 2015
Use the Ruby 1.9 hash syntax in the validates_format_of :email state-
ment.
Minor improvements and corrections of typos.
Version 2.1.4
Version 2.1.4 was released January 3, 2015
Updated references to Ruby from version 2.1.5 to 2.2.0.
Specify the “v0” version of the google_drive gem in the “Spreadsheet Connec-
tion” chapter.
Version 2.1.3
Version 2.1.3 was released December 25, 2014
Updated references to Rails 4.1.8 to Rails 4.2.0.
Version 2.1.2
Version 2.1.2 was released December 4, 2014
Released for sale as a Kindle book on Amazon, with new cover art (same cat,
though).
RailsApps Tutorials now named the Capstone Rails Tutorials.
Updated references to Ruby from version 2.1.3 to 2.1.5.
VERSION 2.1.1 387
Updated references to Rails 4.1.6 to Rails 4.1.8 (minor releases with bug and
security fixes).
Removed link to the (now defunct?) Lowdown web application in the “Plan
Your Product” chapter.
Changes to the “Asynchronous Mailing” section of “Send Mail” chapter to de-
scribe Active Job in Rails 4.2.
Minor improvements to the “Dynamic Home Page,” “Deploy,” “Configure,”
“Troubleshoot,” and “Create the Application” chapters.
Version 2.1.1
Version 2.1.1 was released October 22, 2014
Minor rewriting for clarity.
Updated “Precompile Assets” section of the “Deploy” chapter.
Mentioned explainshell.com in the “Get Started” chapter.
Mentioned Zeal as a Linux alternative to Dash.
Recommended book Practicing Rails by Justin Weiss.
Version 2.1.0
Version 2.1.0 was released October 12, 2014
Updated references to Ruby from version 2.1.1 to 2.1.3.
Updated references to Rails 4.1.1 to Rails 4.1.6 (minor releases with bug and
security fixes).
Four new chapters:
www.dbooks.org
388 CHAPTER 26. VERSION NOTES
• “Testing”
• “Rails Composer”
• “Crossing the Chasm”
• “Level Up”
Version 2.0.2
Version 2.0.2 was released May 6, 2014
Updated references to Rails 4.1.0 to Rails 4.1.1 (a minor release with a security
fix).
For Nitrous.io users, clarify that “http://localhost:3000/” means the Preview
browser window.
Update “Gems” chapter, section “Where Do Gems Live?” to add more expla-
nation.
Minor change to code in the “Mailing List” chapter, setting ‘mailchimp_api_key’
explicitly when instantiating Gibbon, for easier troubleshooting.
VERSION 2.0.1 389
Version 2.0.1
Version 2.0.0
www.dbooks.org
390 CHAPTER 26. VERSION NOTES
Version 1.19
Version 1.18
Version 1.18 was released January 10, 2014
Updated references to Ruby from version 2.0.0 to 2.1.0. Changed one line in
the “Front-End Framework” chapter to accommodate a change in the rails_layout
gem version 1.0.1. The command was:
Changed to:
Version 1.17
Version 1.17 was released December 21, 2013
www.dbooks.org
392 CHAPTER 26. VERSION NOTES
• http://learn-rails.com/learn-ruby-on-rails.html
I’d love it if you mention the book online, whether it is a blog post, Twitter,
Facebook, or online forums. Recommending the book with a link makes it
easier for people to find the book.
Credits
The book was created with the encouragement, financial support, and editorial
assistance of hundreds of people in the Rails community.
Daniel Kehoe wrote the book and implemented the application.
393
www.dbooks.org
394 CHAPTER 27. CREDITS AND COMMENTS
Kickstarter
Thank you to contributors to two Kickstarter campaigns, for the first edition of
the book and for the revision for Rails 5.0.
Technical Editors
Rails and Ruby experts are very busy. I am very grateful for the assistance I
received from my colleagues for the technical review of individual chapters.
www.dbooks.org
396 CHAPTER 27. CREDITS AND COMMENTS
Photos
Images provided by the lorempixel.com service are used under the Creative
Commons license. Visit the Flickr accounts of the photographers to learn more
about their work:
The photo of a fluffy white cat by Tomi Tapio is used in the application.
Comments
I regularly update the book. Your comments and suggestions for improvements
are welcome.
Feel free to email me directly at [email protected].
Are you stuck with code that won’t work? Stack Overflow provides a question-
and-answer forum for readers of this book. Use the tag “learn-ruby-on-rails”
or “railsapps” when you post your question.
Found a bug in the tutorial application? Please create an issue on GitHub.