Twitter Updates

Five Things I Wish I'd Known About Ruby & Rails

Six months ago, I decided to learn Ruby and the Ruby on Rails framework. It was a whim. I dove in feet-first without spending too much time focusing on studying the language. To force myself to solve real problems, I decided to write a real application. Now, with six months of knowledge, here are the things I had known when I started:

1. Naming conventions matter.

Rails is built around the idea of convention over configuration. To that end, naming conventions matter. Rails will do a lot for you, but it needs some hints and relies on well-established Ruby conventions. For example, class names begin with an uppercase letter and generally separate distinct words by changing case (rather than underscores). So, a class for service requests might be named ServiceRequests. If the class represents a model, Rails must map the model to the underlying RDBMS – in doing so, it uses underscores to identify distinct words. Thus, the model implemented in class ServiceRequests is persisted to a table called service_requests. If you inadvertently start by naming your database tables without underscores, you’d end up with a model with the rather ugly name of Servicerequests.

Similarly, Rails uses language inflection rules to attempt to use plural or singular versions of the nouns in your models. So, a singular representation of a service request would be ServiceRequest, where as a plural representation would be ServiceRequests. This works well for English words with standard inflections, but not so well for irregular words. For example, Rails would by default inflect inventory incorrectly to inventorys. These inflections are important in the naming of controllers and in describing the relationships between models. In the case of the inventory model, it’s the difference between saying belongs_to :inventory and has_many :inventories.

Knowing where to Rails inflection rules is important in cases like this – you use files in your config/initializers directory with something like this:

ActiveSupport::Inflector.inflections do |inflect|

inflect.uncountable %w( inventory )

end

(This tells Rails that inventory is an uncountable word, so both the plural and singular version is represented as just plain “inventory”.)

A brief overview of Ruby and Rails naming conventions are here. More information about Rails inflection rules are in this blog entry.

2. Knowing the idioms of Ruby saves time.

Probably more than most other modern languages with the exception of Perl, knowing the idioms of Ruby will save you time. A lot of time. Since most programmers think in their most recent language for the first few months of writing in a new language, it’s natural to fall into the habit of writing code in Ruby thee way you would’ve done it in whatever you’re used to. This can lead to some unnecessarily complicate code that is very un-Ruby.

A basic example is string concatenation. You may be tempted to write:

message_body = “Your user id ” + user_id + ” is now ready for use at ” + site_name “.”

Idiomatic Ruby would use:

message_body = “Your user id #{user_id} is now ready for use at #{site_name}.”

It’s tempting to think that this isn’t that big of a deal. String concatenation the Ruby way provides only marginal benefit in terms of readability and code length, right? That may be true, but there are dozens of examples of similar time savers. Things like built in methods to iterate over collections, using Proc and lambda functions as anonymous procedures, accessor helpers built in to Ruby’s classes to create getter/setter like functions automatically, and  the ||= operator that is essentially a “short-circuit” type operator that returns the left-hand side if it evaluates to true, otherwise it performs an assignment to the left-hand side from the right-hand side.

The bottom line is that it really does pay to spend some time learning the subtleties of Ruby that make it different from other languages. While it’s difficult to teach idioms, there is a great overview in this StackOverflow question.

3.Don’t get too far without learning about testing in Rails.

When I started with Ruby and Rails, I dismissed the idea of learning testing first. I know about unit and functional testing from other languages and I’m familiar with Test Driven Development methodologies. I just figured I’d learn the language and frameworks first and worry about testing later.

I did learn about testing and, in retrospect, I really should’ve taken the time to learn this first. There are lots of testing options with Ruby and Rails and the right one for a project can vary quite a bit. When you’re learning though, just use what comes out of the box. It’s very good. And while you may already know about testing and TDD, it’s instructive to try it the Rails way. Fixtures provide test data for you to use. Tests are split up between functional, integration and performance tests. The Rails Guide on the subject is a good primer – it won’t give you everything you need to know, but it will absolutely give you what you need to start.

There are lots of options when it comes to testing in Rails. My personal recommendation is to read up on shoulda, RSpec, Selenium and Cucumber. Don’t get too caught up in the philosophical debates on the tools. Just understand what is out there, write some tests as you learn, and you’ll be much better equipped to experiment with the wide range of testing frameworks.

There are two tools that are useful no matter what testing framework or approach you use: autotest and rcov. Autotest makes continuous testing painless and it has fantastic integration on Mac platforms with Growl. The rcov tool provides test coverage reports on a source file-by-file level as well as aggregate across your project.

4. Do not write a single line of code until you’ve installed RVM.

RVM, the Ruby Version Manager, is a simple to use tool for managic separate Ruby environments including the version of Ruby and Ruby gems. This makes switching between different configurations of your Ruby and Rails environments painless. It doesn’t seem like that big of a deal, but as versions of Ruby or Rails change, and as you want to experiment with different Ruby libraries, this will make life much easier.

The Ruby and Rails community continues to evolve quickly and being able to keep independent environments is also helpful so you can try new releases without risking negative consequences on an existing installation. RVM is easy to use, even for a beginner, and the 15-30 minutes you spend setting it up will pay off in the long run.

5. Know all the places Rails stashes code so that you Don’t Repeat Yourself.

One of the principle tenants of Ruby and Rails is “Don’t Repeat Yourself” or just DRY. In line with this principle, Rails has a variety of places for code to live so it can be reused. It’s helpful to know what your options are so that you can know the best place to put your code as well as know all the places to look in other people’s code for little nuggets. I spent hours digging through code on Github trying to figure out how something worked because of this.

Here are a couple examples of where code hides out in Rails applications:

  • helpers/ – Helper classes are used to augment views. When you find that you’re repeating code in different actions of the same controller or even within the same view, helpers are a good way to abstract code from the view.
  • config/ – While not specifically a place to store reusable code, some applications will tweak or override default behavior of Ruby or Rails in the config directory. One common example of this is Devise, the gem that is used for providing a rich authentication framework.
  • vendor/ – Used for some Rails libraries.
  • public/javascripts/application.js – This JavaScript file is included with the javascript_include_tag :defaults tag in a view. In addition, Rails will include other JavaScript libraries when you use :defaults though the specifics vary by version of Rails. Generally speaking, you don’t want to do this – it can lead to pages needing to load JavaScript that isn’t necessary, and in some cases, can cause you to load JavaScript that conflicts with your own code. (In Rails 2.x, this happens frequently with conflicts between Prototype.js and jQuery libraries.)

Another confusing aspect to beginners is the inheritance that happens with controllers and helpers: everything in your controllers/application_controller.rb and helpers/application_helper.rb files are automatically included in all controllers and helpers throughout your application while all others are specific to a particular controller.

Conclusion

I’m only six months in to my Ruby and Rails adventure but I’ve really enjoyed learning. Struggling through challenges is a great way to learn so while it may have been helpful to know the things above, I probably wouldn’t have the same appreciation for the language, framework and community as I do now. While I hope this is helpful to someone who is just getting started, it can’t replace hard earned experience. Have patience, don’t give up when you feel like you can’t figure something out, and in six months you’ll be blown away at what you’ve learned.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • LinkedIn
  • Slashdot
  • Twitter
  • Reddit