Practicing Rails Sample
Practicing Rails Sample
Introduction
[This book] is meant to be practical. It is meant for use.
Mindfulness in Plain English
Im addicted to learning.
Right next to me, I see books on code generation, agile processes, statistics, writing,
JavaScript, Erlang, and a lot more. And that doesnt even count the Kindle.
I want to read them all. But if Im not careful, reading them will be a total waste of
time. Ill read one, Ill love it, Ill set it down, and a week later Ill have forgotten
everything in it.
Books are my favorite way to learn something new. But even after buying and reading
tons of books, youll still get lost when you try things on your own. And at that point,
have you learned? Or are you just transcribing?
1. http://www.urbandharma.org/udharma4/mpe1-4.html
It seems so easy when its words on a page. But when you try to transform your ideas
into code, out comes the stress, the frustration, and the worry. You dont have the
time to go over it all again, so did you spend that time learning for nothing?
This happens all the time. Its exactly how I felt learning Rails. Its how I felt when
I first started writing, and playing Go, and using Emacs. But it doesnt have to stop
you.
It is possible to learn Rails without being totally overwhelmed, and without having
the things you learn abandon you as soon as you try to grab ahold of them.
Thats what this book is about. Its a second book of Rails. A companion. Itll show
you how to learn the most in the least amount of time, using the resources you already have. And in the process, Ill guide you through some of the toughest lessons
Ive learned during my programming and Rails career.
Practicing Rails
as Running into a brick wall, constantly. So dont worry if you feel that way
we all do.
If it came easily, it wouldnt feel so great when you get it. Seriously, finally
fixing a problem youve been fighting for the last hour is the best feeling in
the world. So struggling should tell you that youre on the brink of learning
something really valuable.
3. Find the fun.
Every developer I know has those areas of programming that they love to do
more than anything else.
For some people, its data modeling. Have them draw some boxes and lines
on a whiteboard, and they can talk for hours. For others, its seeing their stuff
running on other peoples phones and computers. The magic of deployment.
For me, its refactoring. Taking a chunk of terrible code and turning it into
something clean and beautiful.
Youll have your own preferences. So as you follow this book, search for the
things that really resonate with you, the things you get lost in, the things you
just want to do for hours.
Keep those in mind. Because when you get frustrated, youll have something
you like to do to come back to. Itll remind you why youre doing this, and
help you enjoy some of the fun before you dive back into the frustrating.
Learning isnt just about reading. Its also about action. And thats why you cant
learn Rails without practicing Rails.
4
Chapter 1
Go Proverb
2. http://senseis.xmp.net/?LoseYourFirst50GamesAsQuicklyAsPossible
Practicing Rails
But I dont read programming books on the bus. Because when I do, the information
drains out of my mind before I get home. Instead, I read them in front of my computer, so I can try things out. Sure, it takes longer to get through each one. But whats
the point of reading non-fiction if youre just going to forget it when it matters?
The best way to learn new Rails ideas and techniques is to use them. Right away.
Practice them, internalize them, and make those techniques yours.
Rails gives you two ways to try new ideas right away: generators and scaffolds. With
two lines, you have an entire Rails app ready to use:
rails new test_app
bin/rails generate scaffold some_model name:string
You can try anything: routing, HTML, associations, filters, callbacks, validations, and
everything else.
This isnt an app youll actually ship. Its only there to help you learn. When you generate a tiny app like this, you go from book to playground in seconds. Thats powerful.
That is, Ive generated fifty-two Rails apps, just for trying out ideas I have. I can explore new Rails features, use tricks I learn from blog posts, do research for my articles
and this book, and play with anything else I can think of.
(And those are from after I sort-of-accidentally wiped my hard drive three months
ago).
All of those are just Rails 4.1 or 4.2 apps, using Rails defaults, with one or two generated models. Nothing complicated, just a playground for learning and breaking
things.
Practicing Rails
Wrapping it up
If you really want to learn something, you have to use it. This goes for Rails, too. And
the fastest way to learn new Rails concepts is to scaffold new apps where you can try
them out.
When you explore new concepts in tiny test apps, youll be able to focus on the idea
youre trying to learn. You can try it in different situations. Youll get practice using
it. And you wont have to worry as much about integration pain or errors.
Practicing Rails
10
This gives you a simple app that you can try out in your browser. You can hack on it,
break it, and play with it. You spent almost zero time building it, so you dont have
to worry about screwing it up. You can do anything you want to it!
But scaffolds?
You might hear that Rails developers dont use scaffolds in the real world. I totally
disagree with that. I use scaffolds all the time, even though I could write the code
from scratch. Why?
In real apps, I cant ship great features until I play with them first. With scaffolds,
you can do that without taking much time. If you change your mind about how your
features designed, you can tear it out. No big deal.
And sure, you might replace the scaffold before you ship. But I prefer to spend as little time as possible on the code until Im happy with how a feature works.
I care about getting the most knowledge in the least amount of time, and scaffolds
and other Rails code generators are a great way to do just that.
11
Practicing Rails
12
For example, I wrote an article about Rails validation contexts . I was curious
whether calling valid? twice with different contexts would add to the errors, or if
it would overwrite them. When I investigated it, I never had to start a Rails server. I
used the console instead.
You start a rails console by running bin/rails console inside your apps main directory. Once youre in, you can call methods, define classes, do pretty much everything
youd do in code, and itll just run:
5. http://www.justinweiss.com/blog/2014/09/15/a-lightweight-way-to-handle-different-validation-situations/
13
Practicing Rails
bin/rails console
Loading development environment (Rails 4.1.5)
irb(main):001:0> a = Article
Article.new
=> #<Article id: nil, title: nil, body: nil, author_id: nil,
created_at: nil, updated_at: nil>
irb(main):002:0> a.valid?(:publish)
=> false
irb(main):003:0> a.errors.messages
=> {:author_id=>["can't be blank"], :body=>["can't be blank"]}
irb(main):004:0> a.valid?
=> false
irb(main):005:0> a.errors.messages
=> {:author_id=>["can't be blank"]}
irb(main):006:0> exit
14
First, you can use a lot of Rails features through the app object. app is a special object
6
that has some useful methods for experimenting with your Rails app .
For example, you can try out your routes:
irb(main):001:0> bug = Bug
Bug.create(:name => "Some bug name")
(0.3ms) begin transaction
SQL (2.9ms) INSERT INTO "bugs" ("created_at", "title",
"updated_at") VALUES (?, ?, ?) [["created_at", "2014-11-12
07:51:02.211664"], ["title", "Some bug name"], ["updated_at",
"2014-11-12 07:51:02.211664"]]
(1.2ms) commit transaction
=> #<Bug id: 1, title: "Some bug name", description: nil,
created_at: "2014-11-12 07:51:02", updated_at: "2014-11-12
07:51:02">
irb(main):002:0> app.bug_path bug
=> "/bugs/1"
You can make web requests, so you can run controller and view code:
6. In case youre curious, app provides all of the Rails integration test methods: http://guides.rubyonrails.org/
testing.html#helpers-available-for-integration-tests
15
Practicing Rails
irb(main):003:0> app.get "/bugs/1"
Started GET "/bugs/1" for 127.0.0.1 at 2014-07-09 06:16:21 -0700
ActiveRecord::SchemaMigration Load (0.6ms) SELECT
"schema_migrations".* FROM "schema_migrations"
Processing by BugsController#show as HTML
Parameters: {"id"=>"1"}
Bug Load (0.3ms) SELECT "bugs".* FROM "bugs" WHERE "bugs"."id"
= ? LIMIT 1 [["id", 1]]
Rendered bugs/show.html.erb within layouts/application (17.2ms)
Completed 200 OK in 228ms (Views: 180.7ms | ActiveRecord: 0.3ms)
=> 200
irb(main):003:0> puts app.response.body.first(200
200)
<!DOCTYPE html>
<html>
<head>
<title>Bugsmash</title>
<link data-turbolinks-track="true" href="/assets/bugs.css?body=1"
media="all" rel="stylesheet" />
<link data-turbolinks-track="true" href="/as
=> nil
The console also gives you helper. The helper object provides all of your apps view
and helper methods in the Rails console:
irb(main):005:0> helper.content_tag :h1, "Hey there"
=> "<h1>Hey there</h1>"
helper works with Rails view methods like content_tag and form_for, and any meth-
irb(main):001:0> Article
Article.new
=> #<Article id: nil, title: nil, body: nil, author_id: nil,
created_at: nil, updated_at: nil>
irb(main):002:0> _.valid?
=> false
Here, I didnt need to assign Article.new to a variable, because I could just use _ to
reference it.
The Rails console is the fastest way you can try the things youre learning. Its the
tool I reach for first when I need to try out something new.
17
Practicing Rails
test/models/article_test.rb
require 'test_helper'
class ArticleTest < ActiveSupport::TestCase
test "seeing if errors are overridden when valid? is called twice
with different contexts" do
article = Article
Article.new
article.valid?(:publish)
puts
puts "--After calling valid?(:publish)"
puts article.errors.full_messages
article.valid?
puts "--After calling valid? again"
puts article.errors.full_messages
end
end
This might look weird, because there arent any assertions. And the output isnt that
great to read. But remember, this is just about experimentation. I no longer have to
18
worry about setting up my objects, because all the setup code is in my test file, which
I can run whenever I want.
Focused tests
Ruby has a quick way to run a single test case (or set of test cases). When you run a
single test, you get clearer, faster responses. Using the last example, from your Rails
root, you could run just the test case we wrote:
ruby -Itest test/models/article_test.rb -n "test_seeing_if_errors_
are_overridden_when_valid_is_called_twice_with_different_
contexts"
Lets take a closer look at that command. The -Itest part tells Ruby to look in your
Rails apps test directory when you use require. You need this, because your test
files require test/test_helper.rb, which boots Rails so it can run your test.
test/models/article_test.rb is the name of the test file to run. In Ruby, you can run
a test file as if its just a Ruby script, and itll automatically discover any test cases in
them and run them.
Finally, the -n "test_seeing_if_errors_are_overridden_when_valid?_is_called_
twice_with_different_contexts" tells Ruby which specific test to run.
The name of this method is a little bit different than what you defined earlier. When
you use the test "some friendly name" syntax, Rails does two things to build the
name that you use with -n:
1. Prefix the name with test_
19
Practicing Rails
Instead of running only one test, this syntax will run all of the tests that have
is_called_twice somewhere in the name. This is a lot shorter, but you might run a
few tests instead of just one. In your sample apps, where youre just using tests to try
things out, it probably wont matter.
If you use tests along with a gem called pry , you can use your tests to set up the objects, then open a console with pry. Once youre in the console, you can start experimenting with your code.
If you add pry to your Gemfile:
7. http://pryrepl.org
20
Gemfile
gem 'pry', group: [:development, :test]
you can use binding.pry in your test, wherever you want to enter a console:
test/models/article_test.rb
test "seeing if errors are overridden when valid? is called twice
with different contexts" do
article = Article
Article.new
article.valid?(:publish)
binding.pry
end
21
Practicing Rails
bin/rake
Run options: --seed 19674
# Running:
From: /Users/jweiss/Source/test_validation_contexts/test/models/
article_test.rb @ line 7 ArticleTest#test_seeing_if_errors_are_
overridden_when_valid?_is_called_twice_with_different_contexts:
4: test "seeing if errors are overridden when valid? is called
twice with different contexts" do
5:
article = Article.new
6:
article.valid?(:publish)
=> 7:
binding.pry
8: end
[1] pry(#<ArticleTest>)> article.errors.messages
=> {:author_id=>["can't be blank"], :body=>["can't be blank"]}
Its a console!
You can do most things here that you can do with the Rails console (but you wont
have the app and helper objects). It even has syntax highlighting and some really nice
8
other features . And when you combine it with tests, you can try out new ideas really
quickly.
Wrapping it up
Tiny Rails apps are a great way to try new ideas out in a realistic way. When you use
scaffolds and Rails generators, you can build these apps quickly.
So, when youre introduced to a new idea, generate an app with a scaffold or two. Add
the code youre seeing to the right place in your app.
8. http://pryrepl.org
22
If you can access the code you added without going through the UI, use a Rails console to explore that code. Otherwise, start up your Rails server and try it out through
the UI.
If you start to get annoyed with the amount of setup you have to do, put some of that
setup code into a test. If you combine test cases with pry, you can have your test case
do all of the repeatable setup, and drop you off at the right place to experiment.
Exercise
Take the most recent Rails idea you heard about. (If youre having trouble thinking
9
of one, try something like Active Record Enums ). Start a tiny Rails app using the
process in this section, and get it built and working. Then, experiment with it. How
can you break it? Look up the documentation. Are there any other features you could
try?
9. http://edgeguides.rubyonrails.org/4_1_release_notes.html#active-record-enums
23
Practicing Rails
Youll remember what you read about, because the searches, the error messages
when things break, and the feeling of success when you discover something new, will
all stick with you.
Its so much easier, and a lot more fun, than just reading a chapter in a book. Because
that concept, those ideas, are now yours.
That line will load config/redis.yml, If Im in development mode, itll look for configuration under the development: key inside that file, and so on. Then, itll return
the values under that key as a hash.
Theres a lot you could play with here to answer some interesting questions. What if
you passed a string instead of a symbol? What if you passed a path, instead of just
a filename? Could you find a way to load a .yml in lib/ instead? Could you pass an
absolute path, like /usr/local/etc/redis.yml? What if your .yml file didnt have the
Rails environments defined in it? What if it used yaml includes, like &default? Can
you use ERB inside your config file?
Next, try some of these out, and see what happens.
When you use your curiosity to break things:
25
Practicing Rails
You get to see different kinds of errors when youre expecting them. This is so
helpful: Its so much less intimidating to see an error message when you already know youre going to get an error message, and you start to see certain
messages really often. Youll develop intuition about what they mean. Youll
10
eventually start psychic debugging , where you can tell someone where the
problem is in their code without even looking at it. (This is a really fun way to
amaze and annoy your friends and coworkers).
Youll start thinking of ways to break features without knowing how theyre
implemented. Thats your first step to getting great at writing test cases. And
11
itll really help you once you start practicing Test-Driven Development .
When you break things on purpose, you get more comfortable when things
break. The way to deal with errors is by building curiosity, not fear. Why is
this thing breaking?, rather than How can I make this problem go away!
Wrapping it up
Once you have a good playground for trying something you just learned, use that
playground to own that concept. Explore the boundaries of that concept until you
feel like you really get it.
A lot of the exploration comes from brainstorming questions you have about the feature. Some of these questions will come to you naturally, and others youll have to
think a lot about.
10. http://blogs.msdn.com/b/oldnewthing/archive/2005/12/02/499389.aspx
11. Abbreviated TDD, test-driven development is a mode of testing where you write tests against code that you
havent written yet. You use those tests to tell you how to design your code.
26
If youre having trouble brainstorming questions you have about the feature, use
How can I break this feature? to come up with some ideas.
Once you have some good questions, answer them on your own inside your tiny Rails
app. You wont be able to answer them all, but youll teach yourself a lot by trying.
Practicing Rails
Wrapping it up
So, when youre done playing with your tiny Rails app, dont delete it. Keep it around
as a reference later.
Picking good names for your tiny apps will help you find them when you need them.
Its hard to find out which of test1..test57 is the one that taught you polymorphic
28
associations. A two to three word name is best. Its short enough to scan, but long
enough that each app is focused on one small idea.
6. If you want repeatable setup and a console, use pry inside your tests.
12. http://pryrepl.org
29
Practicing Rails
7. Brainstorm some questions you have about the idea youre exploring.
8. Discover the answers to those questions within your tiny Rails app by modifying the code you just wrote.
30
Chapter 2
Youll know it first by the weird, tingling feeling in your shoulders or legs. Youll get
stressed out by the empty command line and skeleton Rails app on your screen, and
13
have absolutely no idea where to start. Its just easier to hop onto Hacker News and
read a few articles instead. Inspiration has to come sometime, right?
13. http://news.ycombinator.com
31
Practicing Rails
This feeling is totally normal. Whenever Im about to start a new Rails app, I still feel
like I want to give up computers forever and run into the woods or something. But I
have a process to share with you that will help you get past this, so you can turn your
ideas into real, working apps.
Do you want to build a new Rails app from the ideas you have in your head?
Learn step-by-step ways to test your code easily and efficiently?
Know what to do when your apps blow up, and you have no idea how to fix
them?
Know which parts of Rails to learn now, and what you can put off until later?
Get just the important information out of the noisy Rails community?
And keep your motivation fired up, so you can turn mastering Rails into a
habit youll actually keep?
This is the end of the sample. But youll learn all these things (and more) in
the full book of Practicing Rails.
14
14. https://www.justinweiss.com/practicing-rails
32