Rails Tips

I have started, abandoned, and restarted many pet rails projects. All hype aside, I've collected a fair amount of rails idioms. Whenever I come across a problem I know I've dealt with in the past, I usually run a few greps through my past projects to look for an answer. The following pages are disorganized tips of things I have done that are useful.

Testing

RSpec

RSpec is an implementation of Behavior Driven Design (BDD). It's a declarative form of design and test. When I first learned testing, I learned it as imperatively setting up state, doing some actions, and then verifing the end state. The big problems I had with testing was always getting tangled up in complex dependencies between different components. This made it really hard to focus on the system being tested. I'm looking more into using mocks and stubs to replace fixtures and real models when it makes sense to. BDD helps with this because it focuses on beahavior and specification rather than implementation.

Plugins and Gems

Gem Dependencies

I like to have my projects be self-contained. This means that when you check out one of my projects, you should be able to setup your database, do a rake or two, and be on your way.

There are several fixes to this problem. The cleanest one that I've choosen is to update to Edge Rails with:

rake rails:freeze:edge

then follow Ryan's Scraps Gem Dependencies article.

Unfortunately, upgrading to Edge Rails might not be feasible. In this case, one solution is to mimic what Edge Rails does:

mkdir RAILS_ROOT/vendor/gems
gem install FOO --install-dir RAILS_ROOT/vendor/gems

To make your rails app recognize the installed gems, update your environment.rb to look in the newly created subdirectory with config.load_paths.

Another interesting plugin that I haven't looked into is piston which gives you all the advantages of svn:externals, but also allows you to commit local changes to your own repo.

Escaping HTML

See ERB::Util for the following:

Remember that if you wanted to use these in your controller, you have to require and include it. I recommend against using the shorthand versions because it sucks for readability.

Metaprogramming

When I was trying to create a RESTful TagsController with the acts_as_taggable plugin, I created a form that looked like:

<input id="tag" type="text" size="17" name="tag"/>
<input id="taggable[id]" type="hidden" value="14" name="taggable[id]"/>
<input id="taggable[type]" type="hidden" value="Place" name="taggable[type]"/>

When this form was posted, I would get a string for the class of the object that I wanted to tag in taggable[type]. In normal Ruby, you can call Kernel.const_get(classname) to get the Class object for classname. In Rails, this has been simplified further to be just classname.constantize

Inheritance

Namespaced Models:

class Pet < ActiveRecord::Base
  self.abstract_class = true

  belongs_to :person
  validates_presence_of :name
end

class Dog < Pet
  def bark
    "baaw"
  end
end

Cool Syntax

assert_equal 1, Developer.connection.select_value(<<-end_sql).to_i
  SELECT count(*) FROM developers_projects
  WHERE project_id = #{project.id}
  AND developer_id = #{developer.id}
end_sql

Miscellanous