SeaCucumber - JavaScript Testing Tool based on Script.aculo.us

July 30th, 2007

Michael Ward and I are working on extracting the Script.aculo.us Test.Unit.Runner into a rails gem / plugin. We used this testing framework at our last client and we found it very useful. We would like an easier way to use the testing framework (in and our of Rails). We have called the project Sea Cucumber and are hosting it on RubyForge.

RailsRecipe: Preview a Site on a Different Day

July 30th, 2007

Recently we had a requirement to build a preview mode for a Ruby on Rails application. An article might be scheduled to appear on the front page in the future and the editorial staff needed a way to see how the site (front page, calendars, etc.) would look then. Our application works largely off Date.today to determine what content to display. We extended the Date, DateTime, and Time objects to transparently provide a user chosen date for the application as opposed to the system clock.

Ingredient One: PreviewController
This preview mode was activated through a preview controller. The preview action accepts a date parameter and placed that onto the user’s session. Following that the action redirected to the url being previewed.

def preview
  session[:preview] = {}
  if params[:date]
    begin
      date = Date.parse(params[:date])
      date_time = DateTime.parse(params[:date])
      session[:preview][:date] = date
      session[:preview][:datetime] = date_time
      session[:preview][:time] = Time.mktime(date.year, date.month, date.day)
    rescue
    end
  end
  redirect_to(params[:url] || "/")
end

Ingredient Two: Around Filter on ApplicationController
An Around Filter was added to ApplicationController that looked for a session[:date] attribute on all page requests. If the session object was present the filter placed the user’s preview date onto Thread.current.

around_filter :preview_date
def preview_date
    begin
    Thread.current[:preview] = session[:preview]
      yield
    ensure
    Thread.current[:preview] = nil
    end
  end

Ingredient Three: Overriding System Date
The final ingredient was extending Date.today, DateTime.now, and Time.now with an alias_method_chain to use the Thread.current objects when present instead of using the CPU clock.

DateExtension

module DateExtension
  def self.extended(object)
    class << object
      alias_method_chain :today, :preview
    end
  end

  def today_with_preview
    (Thread.current[:preview] and Thread.current[:preview][:date]) ?
        Thread.current[:preview][:date] : today_without_preview
  end
end

Similar extensions were done for DateTime and Time. I would have liked to have only extended Time.now but that was not sufficient when testing Date and DateTime.

This solution transparently made our application behave in a user preview mode. As far as the application was concerned the date was the preview date with little change beyond the above code which plugs in transparently to the rest of the application. Our ActiveRecord queries all keyed off Date.today and our code was not polluted by introducing an ApplicationDate class that we might have been forced to use in Java or .NET.

Failed Turbot Attempt

July 27th, 2007

Monday I attempted to sautee two 8oz Tubot fillets as an adaption from a sauteed whole trout recipe I was interested in. I avoided whole trout because Beth gets picky with the fish having eyes. The main issue was I used the cooking times for the whole trout for the fillets which greatly overcooked them. The result was the fish lost its structure and really had no flavor. I think the Turbot as a whole is such a mild fish you have to have a stronger sauce to cook it in than just the oil, garlic (which I added), and lemon. The trout would likely have had a better flavor as well.

Next time I will pay more attention to the structure of the fish I am cooking (fillet, steak, whole) as well as the cooking method when adapting a recipe. I think with a shorter cooking time the meal might have been more edible if not much more flavor. Beth said it was “okay” but in reality she was likely thinking “i can’t wait for breakfast.”