Category: Rails

  • Fix for fixture_replacement2 when using default methods

    I’ve been using the excellent fixture_replacement plugin for several months now and greatly prefer it over traditional fixtures (yes, even foxy fixtures). fixture_replacement2 adds even more goodness to the party. However, I ran into a problem today when trying to use default_xxx methods in my example_data.rb file:

    module FixtureReplacement
      attributes_for :course do |c|
        c.name = "Geometry"
        c.transcript = default_transcript
      end
      
      attributes_for :transcript do |e|
        e.name = "Joe's Transcript"
      end
    end
    

    In “fixture_replacement language” this says that new courses should receive a default name of “Geometry” and should also receive a new transcript with a default name of “Joe’s Transcript.” The example above follows the format given in the fixture_replacement README. When I attempt to use this config file in my Rails 2.0.2 project, though, I get this error:

    NameError: undefined local variable or method `default_transcript' for FixtureReplacement:Module
    at top level in example_data.rb at line 7
    ...
    

    Why can’t it find default_transcript? I have no idea. Digging into the source code reveals that default_transcript is added to the FixtureReplacement module at runtime, but for some reason it doesn’t ever show up as being available for calling. I don’t have the time or inclination to dig further, but I did find a workaround by changing:

    c.transcript = default_transcript
    

    to…

    c.transcript = c.default_transcript
    

    This makes fixture_replacement happy and all my tests pass. I submitted a patch so hopefully this wrinkle will be ironed out soon. But this should get you by until then.

  • visual_effect bug fix in Rails 2.0

    I noticed something interesting while enhancing Teascript today. I recently upgraded the app to Rails 2.0 which ended up breaking several of the Scriptaculous visual effects that I had been using to highlight certain parts of the page when things changed. This is how I had called visual_effect in the past:

    page.visual_effect :highlight, "activities_list", :endcolor => "'#DDDDDD'"
    

    Notice the extra set of single quotes inside the endcolor value. I had to add these single quotes due to a small bug in the Scriptaculous helper. Apparently, the helper didn’t automatically place single quotes around the endcolor value when emitting JS for the page. Well, the good news is that this has been fixed in Rails 2.0, so I was able to update my visual_effect calls to:

    page.visual_effect :highlight, "activities_list", :endcolor => "#DDDDDD"
    

    The bad news is that this change broke Teascript for several days since I initially didn’t notice what was going on. But all is well now, and I’m happy that I don’t have to add those useless single quotes any more.

  • Introducing the Lindo (response_visualizer) plugin for Rails

    Being at RubyConf this weekend has provided the necessary motivation for me to finally release a new Ruby gem I’ve been building. It’s an extraction from a project I’ve been working on for Relevance.

    I’m a regular user of assert_select in my functional tests. I find myself frequently doing something like this when the assertion is failing and I can’t figure out why:

    def test_something
      post :something
      raise @response.body.inspect
      assert_select "div[id=header]"
    end
    

    Inspecting the response body usually leads me to a solution, but it’s tedious parsing through the huge amount of HTML that gets returned, often in a semi-unreadable format. Enter the response_visualizer plugin (which has since been renamed Lindo):

    script/plugin install http://github.com/adeptware/lindo/
    

    Or clone the project directly:

    git clone http://github.com/adeptware/lindo/
    

    The plugin provides a vr method to your functional tests. When this method is called, the response body is automatically opened in the default browser allowing for easy visual inspection of the page’s content:

    post :new
    vr
    ...
    

    If you’d prefer to jump straight to the source code, passing the :html symbol will open the formatted HTML in the default text editor:

    post :new
    vr(:html)
    ...
    

    This has saved me a lot of time in figuring out why a specific assertion is failing. Instead of parsing through the HTML, I can view the entire page and immediately tell if something is missing or out of place. I find myself calling vr even before I write my assertions now.

    After installing, check out the README file for additional documentation. There is also a GitHub project if you’d like to contribute a patch or fork the code. Enjoy!

  • Use helpers in your Rails PDF templates

    The Rails PDF plugin is a dandy little thing. It wraps the PDF::Writer library for Ruby, allowing PDF templates to be defined like any other Rails view (with a .rpdf extension, of course).

    One thing it doesn’t do is allow access to the parent controller’s helper from within a PDF template. It’s easy enough to patch the plugin to accomplish this, though.

    First, open up vendor/plugins/railspdf/lib/railspdf.rb and take a gander. This is the section we’re interested in:

    ...
    class PDFRender < ActionView::Base
      def initialize(action_view)
        @action_view = action_view
      end
      ...
    

    PDF templates get rendered in the context of this class. All we need to do to gain access to the controller's helper here is include the helper from inside the class initializer, like so:

    ...
    class PDFRender < ActionView::Base
      def initialize(action_view)
        @action_view = action_view
        prefix = action_view.controller.class.to_s.gsub(/Controller/, '')
        self.class.send(:include, "#{prefix}Helper".constantize)
      end
      ...
    

    We first calculate the prefix of the helper based on the class of the controller assigned to the view. Then we include the helper in the current class by constantizing the resulting string.

    We're almost done. Since ApplicationHelper should be available to every controller and helper in the system, let's include it here for good measure:

    ...
    class PDFRender < ActionView::Base
      include ApplicationHelper
      
      def initialize(action_view)
        @action_view = action_view
        prefix = action_view.controller.class.to_s.gsub(/Controller/, '')
        self.class.send(:include, "#{prefix}Helper".constantize)
      end
      ...
    

    And we're done! Piece of cake. Now we can reference methods from inside our controller's helper. We can, of course, modify this hack somewhat so that the same helper (something like "PdfHelper" maybe) is included for all of our templates. This enables us to isolate our PDF-specific helper methods in a single module.

    And before you ask, yes, it's nasty to be modifying the plugin directly. There is a way to inject this patch into the PDFRender class without touching anything in the plugin... but I've gotta leave something for you to figure out! :)

  • Hey, flexmock and unit_record, play nice!

    So you’re savvy with flexmock, a fine Rails plugin that lets you create mock objects in your tests. You’ve been coding up a boatload of fine tests that are elegant in their isolation thanks to your super mocks. They all run fine, but they’re kind of slow so you go Googling for techniques to speed them up.

    You stumble across a wonderful plugin called unit_record that can dramatically speed up your unit tests by disconnecting them from the database. You install it, run your tests, and wham, you get a barrage of error messages like this:

    ActiveRecord is disconnected; database access is unavailable in unit tests.
    

    There could be one or two things going on here. The first possibility is that one or more of your unit tests are still attempting to access the database via a finder or a fixture. This is the most likely case if you’re only getting a few errors. If you’re getting an error for every single unit test in your suite, though, then something else is going on: flexmock is not playing nicely with unit_record.

    The root of the problem is that unit_record attempts to turn off transactional fixtures for your unit tests when you run them, but flexmock hijacks unit_record by defining its own alias chains for setup/teardown.

    I got around this problem by updating my unit_test_helper.rb file to include the following:

    class Test::Unit::TestCase
      self.use_transactional_fixtures = false
    end
    

    It’s unfortunate this has to be done, but it’s a better option than digging into the flexmock plugin itself… especially if you plan on upgrading to a new version of flexmock anytime soon. Don’t forget that you should be disconnecting ActiveRecord in your unit_test_helper.rb as well. This is what my entire file looks like:

    require File.dirname(__FILE__) + '/../test_helper'
    
    require 'unit_record'
    ActiveRecord::Base.disconnect!
    
    class Test::Unit::TestCase
      # Unit_record is trying to do this for us, but since we're
      # using flexmock's test case it patches the wrong class.
      self.use_transactional_fixtures = false
    end
    

    Hope this helps someone who was as equally stumped as I was. Happy testing!

    Update on 12/1/07: After chatting with Jim Weirich (the creator of flexmock) and doing some more tweaking, it became obvious that the problem is not with flexmock but lies somewhere else. I removed all references to flexmock from my code and still had trouble. The transactional fixture switch seems to be getting set between test runs, but I can’t locate where it’s happening. If anyone else finds a solution to this problem, please let us know by posting a comment here.

  • Streamlined turns 0.9

    The latest and greatest version of Streamlined was released a few weeks ago. Lots of new features and bug fixes are included in this release, including a handy (and fully configurable) breadcrumb trail implemented in part by yours truly.

    For those who aren’t familiar with it, Streamlined is sort of like Rails scaffolding on steroids. It lets you quickly and declaratively setup an interface for your ActiveRecord models.

    I continue to be amazed by the amount of code I don’t have to write when I’m using Streamlined. In fact, it’s starting to warp me. Whenever I work on a standard Rails project now, I inevitably begin asking myself why I’m having to write all of these actions to do basic CRUD stuff. Streamlined provides it for free.

    Streamlined is quickly approaching a 1.0 release (hopefully this month) so there has never been a better time to jump onboard. One good way to get rolling is with this post that I made a few months ago.

  • No need to check response when testing redirects

    Early on in my exploration of Rails, I got into the habit of testing that the response code of an action indicated a redirect. It turns out that this check is entirely unnecessary since assert_redirected_to makes an identical check:

    def assert_redirected_to(options = {}, message=nil)
      clean_backtrace do
        assert_response(:redirect, message)
        ...
      end
    end
    

    This is how one of my functional tests might have looked early on:

    def test_index
      get :index
      assert_response :redirect
      assert_redirected_to :action => "list"
    end
    

    This is how the test should be written now:

    def test_index
      get :index
      assert_redirected_to :action => "list"
    end
    

    I recall reading several examples that specifically checked for a :redirect response code before calling assert_redirected_to so it must have been necessary at some point. It’s certainly not necessary anymore. Keep this in mind and save yourself a line or two of code.

  • Getting started with Streamlined (part 1)

    If you were one of the unfortunate souls who missed RailsConf this year, I’m sorry for you. If you happened to be at RailsConf but missed Justin Gehtland’s excellent Streamlined tutorial then you are truly of all people most pitiable.

    On a more serious note, the tutorial was very good and has sparked a lot of interesting ideas for further enhancing Streamlined beyond its already hefty feature set. For those who don’t know, Streamlined is a Rails plugin that brings the declarative goodness of ActiveRecord to the UI. It enhances your views with full-featured scaffolds that include relationship management, quick adding of associated models, and much more.

    If you haven’t played with Streamlined before, why not give it a try? With several fresh screencasts over at the blog, a bundle of new documentation, a new sample project, and version 1.0 on the horizon… there’s no time like the present.

    Getting started with Streamlined is easy…

    (more…)

  • Slides from my RailsConf talk

    For those who may have missed my talk at RailsConf, you can download the slides to get a better idea of what the talk was all about.

    I had a blast, by the way! The audience seemed to enjoy it, and I was pleasantly surprised at the number of questions people had about Teascript and the process of building it. About a dozen people came up to me afterwards saying that they had an idea they were mulling over, and my talk had inspired them to get started on it.

    I’ll probably be writing a couple of follow up articles that go into more detail on how homesteading worked for me. I didn’t have enough time to cover everything I wanted to at the presentation due to the enthusiastic response from the audience. To those who attended, thanks for being there and making the talk a success!

  • RailsConf ’07 wrap up

    Portland is rapidly fading into the distance as I fly back towards Raleigh. I’ve enjoyed the past six days immensely. The Ruby/Rails community continues to surprise me with its passion, dedication, and downright uber-geekiness. The highlight of the conference for me was the time spent between talks and during meals, sharing ideas and experiences with other developers. I’m totally worn out now, but I’m already looking forward to next year’s Conf.

    Not everything was peachy keen, though. There are several things that bothered me about the Conf this year…

    (more…)