Get My Patch Added to Core

Help me out here. I came across what I think is a bug in Rails core. It’s a really small issue, and an even smaller patch. Seriously, it’s only two lines of code, and three new tests — as you can see in the Lighthouse Ticket.

Oh, you want a description? The description I wrote in the ticket wasn’t enough? Fine, I’ll expand a bit here. First, let me state that this issue was only uncovered due to our semi-unorthodox deployment strategy. I say semi-unorthodox because I’ve never read of anyone else using a similar style, but I don’t see an alternative.

Here at work we build apps for two sets of users: the public and our business team. These sets of users see totally different applications; in fact, they aren’t even running on the same boxes. Think of our internal tool as a CMS and Customer Service tool. Instead of writing two applications and making them share models, we have one larger application but can control how it reacts by changing the RAILS_ENV. Our basic configuration contains three environments: development, production and admin (this is a simplification: we also have multiple test environments, but they are unimportant for the sake of this discussion).

To limit what can take place on each environment we have segregated our routes.rb like you see below.

# back end services
if %w(admin development test).include?(RAILS_ENV)
    path_prefix = (RAILS_ENV == "development") ? "admin" : "")
    map.namespace(:admin, :path_prefix => path_prefix) do |admin|
      admin.connect "/applicants/:id", :controller => "applicants", :action => "show"
    end
end

# front end site
if %w(production development test).include?(RAILS_ENV)
    map.root :controller => "applicants", :action => "new"
end

Let’s go over this routing real quick. You’ll immediately notice two blocks, the first being for “back end services” (i.e.: internal business users), and the second for the “front end site” (i.e.: the public). If you look closely you’ll see the only difference between the conditionals for each block is that the first includes the “admin” environment while the second uses the “production” environment.

The issue I ran into stems from line #3. When path_prefix is blank, RouteBuilder generates improper URLs, therefore affecting everything inside the admin namespace.

  • When path_prefix is set, the admin URLs look like: /admin/applicants/1
  • When path_prefix is blank they look like: //applicants/1

That extra slash is a bit of a problem with the way we deploy our “admin” environment. We use some Apache fu to map http://admin/project to the root of the application, meaning our internal users need to go to http://admin/project//applicants/1. This URL is clearly incorrect and should never be generated.

Without the path_prefix we are severely limited in our ability to run the full project in development mode. With the path_prefix set in “development” mode we can view the public portion of the site at http://localhost:3000/applicants/1 and the private part at http://localhost:3000/admin/applicants/1. It should be noted that these two routes go to two completely different controllers, one being in the global namespace, and the other existing inside an Admin module.

Now I know if you payed attention you’re probably thinking: “Andrew, you can get around this with a simple refactor, maybe try this…”

path_prefix = (RAILS_ENV == "development") ? "admin" : nil)

Yes, you’re right, that would work: having the path_prefix set to nil is a simple solution. But, a bug is a bug, and adding an extra slash to a URL isn’t an appropriate thing to do. So please, if you made it this far and you don’t think I’m a raving loon then +1 my patch.

Rails Defaults I Like to Change

When working on larger projects the RAILS_ROOT/app folder structure can be a little restrictive. Lately I’ve taken to adding more sub-directories into RAILS_ROOT/app like, observers, mailers and presenters (check out ActivePresenter and Presenter Pattern if you’ve never heard of it). It’s a simple trivial addition to the folder structure that allows me to keep my sanity. Instead of sifting through 40+ files in the models folder I can quickly drill down to what I’m looking for.

Luckily, Rails is nice enough to have a simple mechanism to do this. Open your environment.rb file and look for the lines that read:

  # Add additional load paths for your own custom dirs
  # config.load_paths += %W( #{RAILS_ROOT}/extras )

Simply un-comment the second line and replace it with something like this:

  # Add additional load paths for your own custom dirs
  config.load_paths += %W( #{RAILS_ROOT}/app/clients #{RAILS_ROOT}/app/observers #{RAILS_ROOT}/app/presenters #{RAILS_ROOT}/app/mailers )

Very similar to moving the Ruby files around, I have also taken to moving some of the views around, specifically, mailer views. I like to keep them near the mailer model, and not in the RAILS_ROOT/app/views path.

This change is also quite easy thanks to the extensibility of the Rails framework. Near the end of your environment.rb file add the following line:

  config.action_mailer.template_root = "#{RAILS_ROOT}/app/mailers"

Tall Mocha, no toppings please

I finally got around to using a mocking library today at work. I chose Mocha to start, no real reason, just the first name to pop into my head. After about 15 minutes (10 reading docs, and 5 coding) I am in love. Seriously, testing has never been this easy. What would have taken me at least 30 minutes to add new fixtures wihtout breaking old tests or screwing anything else up was easily solved in one to 2 lines per test case.

class SupportControllerTest < ActionController::TestCase
  def test_applicant_activated_view
      Applicant.any_instance.expects(:activated?).returns(:true)

      post :create, :applicant => {:last_name => "Leapfrog", :email => "sos_platform@leapfrogqa.com"}
      assert_select "ul.activated"
  end
end

The first line in the above method mocks out the activated? method on any instance of the Applicant class. Isn’t that simple and clean? Without seeing the rest of the business logic I know it might be hard to accept why I need an entire library to help me with this simple boolean method, but trust me, activated? method is actually delegated to another model which is using an ActiveResource object to truly determine the result.

ERB templates of ERB templates

Recursion, every programmers favorite topic. Luckily that’s not what this is about, really. Today at work I was writing a Rails Generator that needed to created <a href=”http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/”>ERB</a> templates for views. It sounded pretty simple, but I hit one stumbling point. How do I make my template an ERB template that generates an ERB template of its own without interpreting all of the tags? After a bit of Googling I started to get discouraged. Then I remembered Rails already does some of this in places like the scaffold generator. I opened up the source and the templates and found an ERB tag I had never seen before <code><%%= do_something %></code>. There it was, the ‘%%’ will tell ERB to treat this as a tag for a future run. It will remove the second % and leave you with the output you expect.

Announcing Plugistrano v0.0.1

Plugistrano is a little project I’ve been pondering for a while. My boss Jeff Cohen came up with the idea a few weeks ago. While in Portland at RailsConf 2008 I made some progress with it, thanks to the help of my coworker Mike.

Check out the github repo. Let me know what you think, fork it, fix it and make it better.

note: I have only tested this (very briefly) with Capistrano 1.4.1. It might not work with 2.0. I will try to test it with 2.0 later

Logging in Rails

When you’re living in the Active* world of Rails (ActiveRecord, ActionController, etc.) you always have access to the ubiquitous logger method. But step outside and you’re stuck dealing with the awkward, and uncomfortable RAILS_DEFAULT_LOGGER global. Often time’s I find myself taking one or both of the following approaches depending on the class I’m writing.

class MadeUp
  class << self
    def logger
      RAILS_DEFAULT_LOGGER
    end
  end

  def logger
    RAILS_DEFAULT_LOGGER
  end
end

Now I know, neither of the methods are complex or long, but how often do you want to type that same handful of lines (and doesn't it just make your code ugly)? Enter my latest and greatest contribution to the world: Loggable.

module Loggable
  module ClassMethods
    def logger
      RAILS_DEFAULT_LOGGER
    end
  end

  module InstanceMethods
    def logger
      RAILS_DEFAULT_LOGGER
    end
  end

  def self.included(receiver)
    receiver.extend         ClassMethods
    receiver.send :include, InstanceMethods
  end
end

Object.send :include, Loggable

Remember to require it somewhere in your code.

Dead Simple Mocks For Unit Tests

Yesterday I was testing a Helper (module) I had written for a Rails app I am working on. I wanted to test the helper directly, and not deal with the whole controller and request/response loop just to verify some simple methods. So I started with something like the following:

class TrackingHelperTest < ActiveSupport::TestCase
    include TrackingHelper

    def test_record_event
        ...unimportant...
    end
end

I ran into a problem almost immediately. Some of the methods in this Helper required access to the request object. At first I thought I went down the wrong path, and would need to test this Helper in the context of a controller. Then it hit me, mock the request up. But do I really need a whole class to store and share some instance variables? After pondering this for a few moments I ended up with something like this:

class TrackingHelperTest < ActiveSupport::TestCase
    include TrackingHelper

    # Mocks
    MockRequest = Struct.new(:query_parameters, :path, :headers, :remote_ip, :path_parameters, :query_string)
    attr_accessor :request

    def setup
        @request = MockRequest.new({}, "/some/location", {"HTTP_REFERER" => "somesite.com"}, "1.1.1.1", {:controller => "some", :action => "location"}, "")
    end

    def test_record_event
        ...unimportant...
    end
end

Struct's are simple to use and allow for quick and easy mocking in unit tests. Try it out in your code next time you don't want to build a full class to do something simple.

GitHub and Me

This weekend a fellow member of Rochester On Rails was nice enough to share an invite to Git Hub. Check out my account, I just published two little plugins I use all the time at work and at home when building Rails apps.

The first is Fixture Manager. This plugin adds a few methods to ActiveRecord classes allowing you to save database contents to YAML (either in your test/fixtures folder, or in cms/fixtures). The plugin also provides a few Rake tasks that wrap these methods as well as a simple static class (FixtureManager) giving you two options as to how you want to save and load your data.

The second is Rcov Task. This plugin contains almost no code, its a Rake task that simplifies running your test suite with rcov (and opening your browser if your in Mac OS X).

Sake and Database Shells

If you haven’t installed Sake yet, stop whatever it is you’re doing and get it running on your system.

Ok, with that done you’ll probably want some sake tasks to actually make this new tool useful. Below is an updated version of one my favorite tasks.

desc 'Launches the database shell using the values defined in config/database.yml'
task 'db:shell' => [ 'environment' ] do
  config = ActiveRecord::Base.configurations[(RAILS_ENV or "development")]
  command = ""
  case config["adapter"]
  when "mysql" then
    command << "mysql "
    command << "--host=#{(config["host"] or "localhost")} "
    command << "--port=#{(config["port"] or 3306)} "
    command << "--user=#{(config["username"] or "root")} "
    command << "--password=#{(config["password"] or "")} "
    command << config["database"])
  when "postgresql" then
    command << "export PGPASSWORD=#{config["password"]} && " unless config["password"].blank?
    command << "psql "
    command << "-h #{(config["host"])} " unless config ["host"].blank?
    command << "-p #{(config["port"])} ") unless config ["port"].blank?
    command << "-U #{(config["username"])} " unless config["username"].blank?
    command << config["database"]
  when "sqlite3"
    command << "sqlite3 #{config["database"]}"
  else
    command << "echo Unsupported database adapter: #{config["adapter"]}"
  end
  system(command)
end

With the above task you be in any RAILS_ROOT and type sake db:shell and be automatically placed into the appropriate database shell with your username/password/host/port setup already. You can even do sake db:shell RAILS_ENV=production.

I can't take credit for this task, in fact I originally found it on the Sake Bomb blog post by Err The Blog. The link found in the comments on that page no longer works, but some googling turned up the source code elsewhere. I've added Postgres and sqlite3 to the mix as it only supported MySQL originally. If you know who the original author is please let me know as I would like to credit them.

Rails is great, but…

Don’t get me wrong, I really enjoy working with Rails, but every now and then something about it bothers me. Josh Susser of has_many :through recently blogged about the sometimes differing functionality of size, length and count in ActiveRecord.

Did you catch that, _differing_. When using the count method on association collections ActiveRecord responds differently based on pervious usage. When you’re working alone or on small code bases this might not be a big deal, you might never run into it, maybe you’d even be able to use it to your advantage. The same could be said for larger projects or working with multiple developers, but it’s far more likely to cause a hard to track down bug.

I understand Rails is an open source project controlled by people with their own interests at mind, so please don’t read this as an attack against them or the project in general. I am not the first person to mention these kind of anomalies in the framework, and probably not the first person to have this thought, but would it make sense to fork the project?

I’m not sure it’s worth forking Rails to make it more “enterprisey” (read: consistent). It would be great to have a stable platform, maybe it would receive better acceptance in the office (ie: maybe my python coworkers wouldn’t pick on it). My biggest concern is that removing all these idiosyncrasies will make it impossible to port future creativity from the original authors. Again, that wouldn’t be the end of the world if such a project could attract new development, but I just don’t see that happening. Any thoughts?

I think I’m going to keep a little list going of the things that irk me about Rails. Each time I come across one Merb gets more and more tempting. I really want to dig into Merb, I’ve yet to get do anything more complex than a few basic tutorials, I just need a project…