Well, scaffolding isn’t everything. There’s much more in Rails to see. This week we take a closer look at what is known as “The Rails Way” of doing things.
We’ve mentioned it in passing, but Rails is based on the Model-View-Controller design pattern. This interaction is played out between ActiveRecord, ActionController and ActionView, or in a different light your data, your logic and your presentation. We’ve had a look at Models so far with ActiveRecord, and how that helps us translate database rows into objects we can work with in our application. So now, let us focus a bit more on the other two parts of the equation.
Controllers, bridging the gap between Models and Views
When users visit your application, say visiting a page like /shows/list
, Rails reacts by reaching for app/shows_controller.rb
(matching /shows/
) and within that file running the action list
and passing the results to the templates associated with app/views/shows/list.rhtml
. The purpose of actions can include manipulating and selecting objects from your data models. Controllers allow you to reach into your models and collect the data you need to build your views. Working the other direction, they also allow input received from your views to be processed into workable data for your models. Controllers are really the workhorse of your application, the go-to, production assistant, “go get my coffee” position. Be good to your controllers.
ShowsController < ApplicationController
def list
@shows = Show.find(:all)
# @shows now holds an array of show objects that will get passed to
# your show templates to display and output to the user
end
The above code works by calling the Show
object, finding :all
rows from the database and saving them as an array of Show
objects in the instance variable @show
, which will get passed along to the associated rhtml templates. Here’s how you might display the results to the user with app/views/shows/list.rhtml
:
<h2>My shows</h2>
<div id="content">
<ul>
<% for show in @shows %>
<li><%= show.name %> - <%= show.description %></li>
<% end %>
</ul>
<%= link_to('Add New Show', { :action => :new }) %>
</div>
First off you probably noticed the ERB syntax for embedding Ruby into html, which is denoted by <% _ruby expression_ %> and <%= _print ruby value_ %>. The most action is happening with our for
loop printing out the attributes of each Show
element in shows
. Note that the for
statement is enclosed in <% %> with no = sign, since it's plain ruby code. The <%= %> gets used to output values like show.name
and the result of link_to
a oft-used url helper function that will return a html link based on the parameters set. The end result is a html page that looks like:
<h2>My shows</h2>
<div id="content">
<ul>
<li>The Closer - sweets-loving detective</li>
<li>American Idol - simon hates you</li>
<li>Veronica Mars - snarky, kick-ass sleuth</li>
<li>The Amazing Race - race around the world</li>
</ul>
<a href="/shows/new">Add New show</a>
</div>
If this was something that you used a lot, found in several places with little variation or just might be nicer in a method call then we can put it in a helper. There’s a helper created for each controller as well as application_helper
, so when we visit /shows/*
we activate the application_helper
and the shows_helper
. If we want to move the listing code above into a method it might look like this:
module WeeksHelper
def shows_listing(shows)
html = shows.collect do |show|
"<li>#{show.name} - #{show.description}</li>"
end
content_tag('ul', html.join("\n"))
end
end
And here’s the change to list.rhtml
:
<h2>My shows</h2>
<div id="content">
<%= shows_listing(@shows) %>
<%= link_to('Add New Show', { :action => :new }) %>
</div>
Making Beautiful Code
One of the great side effects of working with Ruby and within Rails, is that many good coding practices tend to rub off on you. For more on treating code as a craft, check out The Pragmatic Programmer by Dave Thomas and Andy Hunt. It’s a great book about building up your programming skills and talent to a new level of passion and artsmanship.
Due to the concise, terse and readable way that one can produce Ruby code, bad code often sticks out like a sore thumb. Your goal as a Rails artist is to track down and replace these sore spots of code. Here’s a few valuable tidbits that will help you in your noble quest.
Version Control
We’ve mentioned it before, but it deserves it’s own headline. Use version control for your source files, config files and whatever file-based information is often changing, necessary for deploying your application from scratch or just isn’t tied down properly. It’s probably better if it’s versioned than if it’s not and would you really want to find out the hard way?
The benefits of using version control can multiply quickly if you are working with other people. The ability to fall back on older code, simple storage of shared code and the ability to easily merge differing versions of code can’t be overlooked.
Tips for Working with Subversion:- A collection of tips for using Rails with Subversion
- You may want to setup a separate repository for each project. If several projects work together a lot or are updated together, then sharing a repository is probably helpful.
- Don’t store passwords in version control (eg.
config/database.yml
) - Store example config files over the real thing (eg. config/database.yml.example instead of database.yml)
Fix Broken Windows
Ever been in one of those super spotless houses, with the huge dining table and nice china sets? Were you sure to do your best to keep everything clean and in order while you were there? Probably, nobody wants to eat the last cookie and nobody wants to be the person who left the muddy footprint on the freshly mopped floor. Code can work like that too, keep it clean and lean and encourage your teammates to do so as well.
Tips for Keeping Code Clean:- Avoid shortcuts. “If I just do this then everything will be okay…” until a week later when your shortcut breaks and causes a bigger mess. The time it takes to clean up after bad code is often greater than the time it takes to do it right in the first place
- Don’t leave broken/unfinished code. As hard as it is to say goodbye, sometimes it better to wipe out the code you’ve been working on and start fresh later.
- Document what you’re doing as you go along. If you make a mistake, fiddle with it for hours and then fix it then it deserves at least a line in your blog, journal, notebook or whatever. In all likely hood, you may see this problem again and if you don’t then someone else will.
- Keep your code flexible, you may start down one path only to backtrack and take another (eg. choosing a database; by using migrations we can easily change our minds about what database to use in the future).
Stay DRY (Don’t Repeat Yourself)
This bit comes up a lot in the Ruby world. The principle is simple, the less code there is, the easier it is to maintain. If you find code, the same or very similar code, in mulitple places then your best bet is to eliminate the repetition. By reducing the places repeated code lives, you make it much easier to maintain that code because instead of tracking down every instance of some code you only need look in one place. This philosopy can be expanded further to include configuration and metadata. Why keep the same metadata in three places? To make life easier, keep the metadata in one place and write scripts to generate what is needed elsewhere (eg. generating documentation from comments with RDoc).
Testing
Are you sure you’re code works? Would you like to be really sure, or better yet confident that it works? Then test your code, and test it whenever you change something or even before you change something. Use a testing suite. This will give you a nice system to work with and allow you to streamline your tests. Be brutal. Try to break your code. If you find a bug, then write a test to trigger it. If your fix works, the test will pass and you’ll have a way to see if that bug ever creeps back. When you get the zen of testing, try writing the test before you write the code. This way, you’ll know when the code works and you’ll already have the test. Anytime the code changes, you will have a system in place to ensure that nothing is broken.
Rails Best Practices
Much of this area is still being explored. Rails is so new and it’s rapidly changing. This is a great time to search, write and discuss what works best. This is a great time to become an important light in the community.