Author: Matthew

  • Validation assertion added to test_spec_on_rails

    I’ve added a new assertion to test_spec_on_rails that enables verification that validates_presence_of is being called correctly on your ActiveRecord models. For example, say you have a model like this:

    class User < ActiveRecord::Base
      validates_presence_of :first_name, :last_name
    end
    

    You would typically test this validation by leaving a field blank, calling valid? or save on the instance, and checking the errors collection for messages:

    describe "User" do
      it "should validate presence of first name" do
        user = User.new(:first_name => nil)
        user.valid?
        user.errors.on(:first_name).should == "can't be blank"
      end
    end
    

    Aside from being tedious to write, this method of testing isn't very fast. With the latest version of test_spec_on_rails your test becomes:

    describe "User" do
      it_should_validate_presence_of :first_name, :last_name
    end
    

    Nice, simple... and fast. Behind the scenes, validation reflection is being used to ensure that validates_presence_of is being called on the model class. The model itself is never instantiated which speeds things up. The test itself is also very clean and easy to read. (You can't get much cleaner than a single line of code, right?)

    What about verifying options that are passed to the validation? This new enhancement handles that too:

    class User < ActiveRecord::Base
      validates_presence_of :ssn, :if => :ssn_required?
    end
    
    describe "User" do
      it_should_validate_presence_of :ssn, :if => :ssn_required?
    end
    

    If the options passed to the assertion aren't used on the actual validation then the test will fail.

    Ready to start rolling with this new hotness? test_spec_on_rails is now on Git so unless you're running Edge Rails you can't use script/install to grab it. My suggestion is to clone from Git into vendor/plugins and then svn:ignore the .git file:

    git clone git://github.com/pelargir/test_spec_on_rails.git vendor/plugins/test_spec_on_rails
    svn propset svn:ignore .git vendor/plugins/test_spec_on_rails
    
  • Why does tabbing skip certain form fields in OS X?

    Isn’t it incredibly annoying how both Firefox and Safari skip select fields and check boxes while keyboard tabbing through a form? Fortunately, there is an incredibly simple solution. (The fact that this isn’t a default setting in OS X makes me wonder if the Apple people wrote that particular preference pane on a Friday.)

  • Contra dancing

    I went contra dancing with some friends last Friday. I’ve done English country dancing before, but never contra. It’s quite a workout, but really fun. Our friends were kind enough to post this video from the event:

  • Building arrays of similar objects in Ruby

    I often find myself having to build arrays of similar objects in my tests. For example:

    def create_user
      :some_user
    end
    
    users = [create_user, create_user, create_user]
    

    It seems wasteful to repeat the same method call three times. One solution is to use the #times method to append to an array, like this:

    users = []
    3.times { users << create_user }
    

    This just doesn't seem very elegant, though. It feels like I should be able to collect the results from each method call with a single line of code. I experimented with the multiplication operator to see if it might be able to do what I wanted, but didn't get far.

    Here's one possible solution I came up with:

    class Integer
      def of
        result = []
        times { result << yield }
        result
      end
    end
    
    users = 3.of { create_user }
    # returns [:some_user, :some_user, :some_user]
    

    The #of method can now be called on an integer. It uses #times to call the given block three times and appends the result to an array which is then returned. Much more elegant. Another way to achieve this on a single line is:

    users = (0..2).to_a.collect { create_user }
    

    This doesn't feel as nice to me. It's visually complex and, at first glance, the zero-basing of the range hides the fact that we're collecting three items, not two. The benefit is that no reopening of the Integer class is required.

    How would you solve this problem?

  • How to filter model data before rendering in Streamlined

    One question that seems to come up a lot on the Streamlined mailing list is how best to filter the records that are displayed in the list view using a certain set of conditions. There are several ways of doing this, but the simplest way is to use Rails’ built-in scoping methods in conjunction with an around filter.

    For example, say we have a Task model and a TaskController that is Streamlined-enabled. The TasksController will display a list of all Tasks in the system by default. What if we only want to display Tasks for the currently logged-in user? Something like this would work:

    around_filter :scope_by_user, :only => [:list, :index]
    
    def scope_by_user
      Task.find_with_user_scope(current_user) { yield }
    end
    

    Once this code is added to the TaskController, any calls to Task#find within the associated actions, views, and helpers will be scoped. Only tasks belonging to the current user will be listed.

    What if we still want to perform an unscoped Task#find within an action? We can eliminate the scoping for a specific block of code using the #with_exclusive_scope method. It looks like this:

    Task.with_exclusive_scope { code_that_should_not_be_scoped }
    

    And that, folks, is how easy it is to filter lists in Streamlined.

  • Is Communism really dead?

    I found Misreading the Tea Leaves by J.R. Nyquist to be pretty thought-provoking. Maybe you will too.

  • raleigh.rb has a podcast

    Did you realize that Raleigh’s own Ruby Brigade now has a podcast? Yes ladies and gents, it’s true.

    I’ve been recording the last few meetups on my MacBook. The audio quality isn’t half bad. I hope to expand the podcast in the future with non-meetup content. For now, it can serve as a good way to catch up if you’re out of town or otherwise can’t make it to our regular monthly meeting.

  • Using named routes in Streamlined addition files

    For you Streamlined users out there, here’s an easy way to include named routes in your Streamlined addition modules. Previously, you had to hard code the URLs like so:

    module OrderAdditions
      def name_link
        link_to user.name, "/users/show/#{user.id}"
      end
    end
    
    Order.class_eval do
      include OrderAdditions
      include ActionView::Helpers::UrlHelper
      include ActionView::Helpers::TagHelper
    end
    
    Streamlined.ui_for(Order) do
      list_columns :name_link
    end
    

    By including Rails 2’s new ActionController::UrlWriter module, you can access any named or RESTful routes you’ve defined in routes.rb:

    module OrderAdditions
      def name_link
        link_to user.name, user_url(user.id)
      end
    end
    
    Order.class_eval do
      ...
      include ActionController::UrlWriter
      default_url_options[:host] = APP_HOST
    end
    

    It would be nice for this to get baked into Streamlined somehow so UrlWriter automatically gets included, but until that happens this is a good way to get rid of those pesky hard-coded URLs.

  • Bill Gates wants to annoy the whole world with Windows

    Yes, it’s true. Bill Gates wants to annoy the whole world with Windows.