• Frequent disconnects with your Linksys router? Try custom firmware

    I have a rather old Linksys WRT54G (v2.2) wireless router that used to disconnect rather frequently for no apparent reason. It is almost guaranteed to get disconnected when I go crazy with using Axel to download files.

    The worse part of the entire "router disconnected" thing is how it takes down my DSL connection (provided by my ISP, Singnet Broadband) with it - trying to reconnect the DSL modem takes upwards of 3 minutes (I imagine it takes awhile for the ISP's network to realize that my DSL connection is really down).

    A few months ago, I finally couldn't stand it any longer and decided to install custom firmware on the router to see if it fixes the problem (which is quite prevalent). I was unwilling to go down this route considering my bad luck tinkering with firmware and drivers (having broken a cable modem and a near-functional Linux install before).

    Linksys WRT54G


    Anyway, long story short: I installed Tomato Firmware and am enjoying rock solid stability! I can run Axel (10 simultaneous connections) with 2 torrents running and still surf comfortably and even download more stuff through the plain old web browser interface.

    Long story, er, long: I tried out DD-WRT first (since we use the same at work), didn't like its bloated interface, and especially didn't appreciate reading (old) allegations about how DD-WRT's author tried to screw the Open Source community over. So I flashed the firmware to Tomato Firmware and ended up loving its minimalist interface and faster restart cycles (most of the time, since Tomato tries to restart as few services as it needs to when you make configuration changes, rather than reboot the entire router like DD-WRT does).

    So, if you're experiencing the same troubles with your Linksys router and haven't had taken the leap of faith with custom firmware, I really recommend you do so. Big warning: Read the installation instructions! Not all WRT54G routers are compatible with Tomato Firmware.

    More reading: Lifehacker has a walkthrough of Tomato Firmware's features (and also one for DD-WRT).

  • Living on the edge (of Rails) #5 - better eager loading and more

    Another week of edge Rails changes, featured on the Rails Envy podcast. This weeks’ report covers changes from 21 Jan 2008 to 27 Jan 2008 (the day the Rails Envy podcast was recorded).

    Eager loading :includes does pre-loading

    The current gem Rails behavior when loading associations with something like

    Author.find(:all, :include => [:posts, :comments])

    is to make a big query with multiple joins that fetches all the associations in the same query (for you RDBMS geeks, the "cartesian product").

    Frederick Cheung (fcheung on the Rails Trac) has contributed an impressive optimization to this by pre-loading the associations rather than trying to eager loading with one big query. So a find like this:

    Author.find(:all, :include => [:posts, :comments])

    would first load all the authors, then all the posts, and then all the comments in 3 smaller, faster queries.

    The main benefit of this (depending on your data): Running X simple queries (to fetch authors, then posts and comments) rather than one mega-query that joins all the associated tables is faster most of the time. The result set is often smaller as well.

    More details can be found at ticket #9640 on the Rails Trac.

    Related changeset: http://dev.rubyonrails.org/changeset/8672

    composed_of aggregations can now be used in finder conditions

    You can now use value objects that you've previously specified that your model is composed_of in the finder conditions hash. E.g. if you have a Customer that has a balance aggregation:

    class Customer < ActiveRecord::Base
      composed_of :balance, :class_name => "Money", :mapping => %w(balance amount)
    end

    You can now pass a Money value object to Customer#find:

    Customer.find(:all, :conditions => { :balance => Money.new(20, "USD") })

    Convenient.

    Related changeset: http://dev.rubyonrails.org/changeset/8671

    New helper: label_tag

    A label_tag helper has been missing for quite awhile since the label helper was added. No longer:

    label_tag 'name'
    # => <label for="name">Name</label>
    
    label_tag 'name', 'Your name'
    # => <label for="name">Your name</label>

    Related changeset: http://dev.rubyonrails.org/changeset/8685

    New ActiveSupport class: ActiveSupport::TimeWithZone

    A new ActiveSupport::TimeWithZone class has been introduced to make timezone support in Rails easier. Ryan Daigle has a good writeup on this.

    A word of warning though: this is still work in progress, as Geoff Buesing, the core team member responsible for these timezone changes, has more to add on how his plans for the timezone puzzle in the comments.

    Related changeset: http://dev.rubyonrails.org/changeset/8696

    map.root can be easily aliased

    map.root now accept a single symbol as an argument to declare an alias. Just a little something to keep your routes a little more DRY, e.g.:

    map.new_session :controller => 'sessions', :action => 'new' 
    map.root :new_session

    Related changeset: http://dev.rubyonrails.org/changeset/8738

    As usual, let me know of any inaccuracies or any suggestions you may have in the comments!

  • Trying code blocks in Ruby (aka Prototype's Try.these)

    Prototype's Try.these is a really useful bit of code (though I doubt it sees much application outside of JavaScript libraries). I have this evil bit of code somewhere, for example:

    var results = Try.these(
      function() { return response.responseText.evalJSON(true); },
      function() { return eval('(' + response.responseText + ')'); }
    );

    Evilness personified in its evaled glory, but that's besides the point here.

    Just for fun, I tried to do this in Ruby, just to see how easy it was, and came up with this try method:

    module Kernel
      def try(*these)
        raise ArgumentError, 'try requires at least 2 arguments' if these.size <= 1
        fallback = these.pop unless these.last.respond_to?(:call)
        these.each { |candidate| begin return candidate.call rescue next end }
        fallback || raise(RuntimeError, 'None of the given procs succeeded')
      end
    end

    Which you can (ab)use like this:

    try(
      Proc.new { open('http://finance.yahoo.com/foo/') },
      lambda { open('http://finance.google.com/bar/') },
      proc { open('http://finantiq.com/flomp/') },
      :fallback
    )

    Real world applications would be, like the example above, retrieving content from several unreliable websites to retrieve currency rates.

    You can find the specs for Kernel#try here: http://pastie.org/144339.

    So the question now is, is there a better way to implement this, or a more idiomatic Ruby way?

  • Songza - finally an easy way to listen to boy band music

    Songza's quite nice, especially after us non-US users lost access to Pandora. Now I can finally listen to some boy band music when I feel like it (because I don't have any in my library).

  • Rails and penis enhancements

    Funniest bug report I've seen on the Rails issue tracker: http://dev.rubyonrails.org/ticket/10919. Be sure to read the comments, and the resolution:

    I appreciate that penis enhancements are the norm for most of the commenters here, but their use is definitely not widespread enough to justify fixing this.

subscribe via RSS