Category: Rails

  • test_spec_on_rails goes Git

    The test_spec_on_rails plugin, which provides some nice helpers for testing Rails applications when using test/spec, has moved from Subversion to Git.

    Check out the profile page or clone the repository itself from this path:

    git://github.com/pelargir/test_spec_on_rails.git
    
  • 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
    
  • 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.

  • 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.

  • Fix for Streamlined menu rendering in Rails 2

    I noticed an interesting side effect of the default behavior of Rails today. A fresh Rails 2.0.2 app includes a line in app/controllers/application.rb that looks like this:

    helper :all # include all helpers, all the time
    

    It looks innocuous enough, but this line can actually cause some unexpected behavior when overriding Streamlined’s streamlined_top_menu and streamlined_side_menu helper methods on a controller-by-controller basis.

    I had two Streamlined controllers setup, one for users and one for roles. I defined the users side menu and the roles side menu to each have certain links, like so:

    # users_helper.rb
    def streamlined_side_menu
       # stuff here
    end
    
    # roles_helper.rb
    def streamlined_side_menu
      # different stuff here
    end
    

    When I visited the users controller, I saw the menu contents for the users controller. When I visited the roles controller, however, I saw the menu contents for… the users controller. What was happening was that ALL the helpers were being loaded for each controller, which meant that the streamlined_side_menu method defined in the roles helper got overridden by the users helper since the users helper was loaded after the roles helper.

    Removing helper: all fixed the problem for me.

  • Growth in Ruby jobs relative to Java

    This is one of the reasons I’m doing mostly Rails consulting right now.

  • Default methods fixed in fixture_replacement2

    The problem I recently blogged about has been fixed in fixture_replacement2. Thanks, guys!

  • Layout assertion added to test_spec_on_rails

    After contacting Rick with my patch, he offered to give me commit access to the project. I took him up on the offer, so the layout assertion is now in there.

    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
    
  • Add layout checking to test_spec_on_rails

    test_spec_on_rails is a plugin that adds Rails-specific assertions to test_spec, allowing you to do nifty things like this:

    it "should render with foo template" do
      get :some_action
      template.should.be "foo"
      # equivalent to assert_equal "foo", @response.template
    end
    
    it "should display foo on page" do
      get :some_action
      page.should.select "p", "foo"
      # equivalent to assert_select "p", "foo"  
    end
    

    One thing test_spec_on_rails is missing, though, is the ability to check the layout that a template renders with. For example, it would be nice to do this:

    it "should render with foo layout" do
      get :some_action
      layout.should.be "foo"
      # equivalent to assert_equal "foo", @response.layout
    end
    

    I’ve submitted a patch to Rick Olson that adds this capability. I’m not sure if or when it will get incorporated into the plugin though, so I’m posting the patch here for anyone who might need it.

    To apply, right-click on the link and download the file into your vendor/plugins/test_spec_on_rails folder, then run this command from inside the same folder:

    patch -p0 < add_layout.diff
    

    Assuming your plugin isn't checked out as an external, you'll be able to commit the changes to your own repository. You can then start using the new hotness as described above. Enjoy!

    Update: Rick made me a committer so I was able to add this myself.