Rails 2.3.3 + mocha = confusion

I just updated a project to Rails 2.3.3 for the cool new “touch” feature, and saw here that I needed to update to Mocha 0.9.7. I did that, but found that my tests were failing – I got lots of NoMethodError: undefined method `stub’ for #<SomeTest:0×7f2c1d921f80> errors.

In my project, I’d declared my dependence on the Mocha gem in my config/environment.rb file, so that “sudo rake gems:install” would load everything required for development in one shot (which is why the dependency isn’t in config/environments/test.rb). I’ll cut to the chase: I needed to add an extra option to that declaration:

config.gem 'mocha', :version => '=0.9.7', :lib => false

The problem is that mocha configures itself based on what test library you’ve already included when you require Mocha. Unfortunately, the config.gem declaration causes mocha to be loaded before Rails has loaded Test::Unit, so Mocha doesn’t configure itself… so no “stub.” Setting :lib to false postpones loading Mocha until you actually do it in your test/test_helper.rb (or wherever).

3:48 pm — GeekeryComments (2)

Automatic wireless goodness

I often work in coffeeshops and other places that provide free wireless networks. Since anyone could sniff traffic sent over these networks, I’ve set up my own virtual private network at home so that my traffic will be encrypted before it leaves my laptop, then decrypted on a server at home and sent out from my home network – this also gives me secure access to a couple of machines at home that aren’t otherwise accessible from the internet. I use OpenVPN for this; it’s open-source, it was relatively easy to set up on my Ubuntu server, and there’s good support for OpenVPN in the Network Manager included on my laptop (also running Ubuntu).

This worked great for a while, but a few things bugged me:

  • The VPN connection doesn’t happen automatically – I had to remember to do it, and would sometimes forget;
  • my favorite hangouts’ wireless networks ask me to accept terms of service every time I use them, and that got annoying;
  • and whenever the DHCP lease renews (which is every few minutes in some places), the DNS server configuration would be reset to point at the shop’s DNS server instead of the one I run (so I’d lose the ability to refer to my home machines by name; it’s also possible that the public DNS server is less secure than mine, so that’s not good).

I set out to remedy these problems, and it turned out to not be too difficult; I learned a bit about Network Manager in the process, too. Network Manager can automatically run a script when it associates with a wireless network, so I wrote this Python script; it solves the first two problems: it looks to see what network we associated with, and if it’s not my home network, it creates the VPN connection. First, though, if it’s one of the networks that requires a terms-of-service acceptance, it accepts them and submits the form. (The latter mechanism is specific to the Portland Telco Project networks we have here in Portland, but you can probably figure out how to customize it to your own networks – if not, leave a comment.)

The third problem, where DHCP renewal clobbers DNS settings, seems to be known but unfixed: here’s a bug about it. The person who reported the bug posted a workaround for this problem. I’m not sure it’s the right change for everyone, but I’m happy with it in my case: it’s a one-line addition to /sbin/dhclient-script; insert this line just after the start of the make_resolve_conf function that’s first in that file:

[ "$reason" = "RENEW" ] && return

This shortcuts the function that would be overwriting the DNS settings to do nothing if we’re renewing the DHCP settings. (Admittedly, if the DNS server addresses changed, I wouldn’t know about it, but my home DNS server’s address hasn’t changed in a while, and I wasn’t in a coffeeshop when it did.)

With these mechanisms in place, I can open my laptop and see Network Manager’s progress by looking at its icon in the menu bar: I see it associate with a network and go through the VPN connection process, without me having to do anything. Perfect.

[Update: Almost perfect: in cleaning up the script for posting, I broke it — I've fixed it.]

3:29 pm — GeekeryComments (5)

My “Day On”

Today on Martin Luther King Day, I participated in Day On, yet another great Portland tech community event: local geeks gathered at CubeSpace to volunteer to help non-profits with technical issues. A couple of dozen folks showed up to offer help, and though only a few folks came by to ask for assistence or asked using the Day On website, a great time was had by all, and we hope the event will continue and grow.

I was one of several folks who got to help Dean Suhr of the MLD Foundation, a resource for families affected by Metachromatic Leukodystrophy; one page of the Foundation’s website displays a Google map showing families affected by the disease, and the map display wasn’t working right. I was able to find a workaround for a problem in a map-display library, and I’m hoping to work with the library’s developer to help fix the underlying problem.

After I showed Dean my fix, I got an unexpected bonus: Dean mentioned that he was considering using Google Maps’ “clustering” feature, which allows a single symbol to represent many individual map tacks when zoomed out to show a large map area — it’s a feature that helps reduce map clutter when a map holds a lot of symbols.

Dean had thus far elected not to use this feature — instead, when zoomed out, he’d used a smaller version of the butterfly symbol that represented each family, to help each individual family show up better on the big map. As he told me this, I thought about the effect of the disease on Dean and his family, multiplied by each of these families, and thought that Dean had already chosen the perfect representation (and said so).

I was lucky to be able to volunteer today, lucky to meet Dean and help a little with the Foundation’s site, and especially lucky to make that connection between the work today and groups like Dean’s who help so many people. Tomorrow I’m getting up early to head back to CubeSpace to watch the Inauguration with more of my Portland tech community friends, and I feel even more strongly that I’m lucky to be part of such a terrific community.

11:50 am — Around Here, GeekeryComments (4)

Fixing a little VPN annoyance

I’m writing this in a coffee shop, and when I’m using a public wireless network, I like to secure my network traffic using a virtual private network (VPN) that I set up on my server at home. Without this, anyone else close by could spy on what I’m doing (including seeing passwords I’m sending to badly-secured web sites). Unfortunately, the connection appears to go bad after a short while, and it took me weeks to spend the minute it took to find a fix.
(more…)

11:54 am — Geekery, ToysComments (1)

The Android fonts on my desktop are beautiful

Droid family font sampleI’ve been tinkering with developing software for the Android phone platform (and loving my G1 phone that runs it)… the Android folks at Google hired Ascender to create a new font family for the phone, the only family that the phone comes with. Here’s a sample from Ascender’s press release.

It occurred to me that because the fonts were designed for legibility at small point sizes, Droid Mono might be a good replacement for the terminal font I do much of my programming in. It turns out that the whole family makes excellent replacements for the default fonts on my Ubuntu systems: they’re so legible that I’ve been able to reduce the default sizes as well, effectively giving me more screen real estate. Several times in the last couple of days, it’s occurred to me how much more beautiful my working environment is, now that I’m looking at a well-designed font.

You can get the fonts from within the Android SDK, but another helpful blogger has put them up as a separate download. (If you’re installing them on Linux like I did, put them in a folder in /usr/share/fonts, then do “sudo fc-cache -f -v” to get the system to notice them.)

11:15 am — GeekeryComments (2)

Android AIDL regeneration

I’m working on a couple of Android projects; one has an Android IDL file (.aidl) for a service, and for some reason, the development environment didn’t automatically generate the corresponding .java file from it. I wasn’t able to figure out what caused this, and recreating the .aidl file didn’t fool the IDE into doing it, nor was I able to find a solution to this with the usual Googling.

I did find that right-clicking the project in the hierarchy and choosing “Android Tools” -> “Fix Project Properties” fixed this. Subsequent changes to the .aidl file automatically regenerated the .java file, too, so that’s nice.

12:37 pm — GeekeryComments (0)

Clearing apt-cacher’s cache

I frequently reinstall Ubuntu from scratch, so I’ve set up apt-cacher on my fileserver to cache the packages I install – this not only reduces my impact on the mirrors, but also speeds up my installs.

Occasionally, though, I see strange problems during installs: apt-get install retrying the download of an apparently-cached package. I haven’t figured out what’s wrong, and frequently I just want to get the reinstall going again. In these situations, it seems optimal to just dump the cache and start over; I haven’t found clear documentation of how to do this, but in case it isn’t obvious, this works for me (my cache is in /var/cache/apt-cacher, and I run it as www-data):

# Stop the service
sudo /etc/init.d/apt-cacher stop
# Move the old cache out of the way, so we can delete it 
# in the background (it can take a while)
sudo mv /var/cache/apt-cacher /var/cache/apt-cacher.old
sudo rm -rf /var/cache/apt-cacher.old &
# Make the new cache hierarchy, and set its ownership properly
sudo mkdir -p /var/cache/apt-cacher/{headers,import,packages,private,temp}
sudo chown -R www-data:www-data /var/cache/apt-cacher
# Restart the service
sudo /etc/init.d/apt-cacher start

Update: I found this blog post helpful for manually removing troublesome packages from the cache.

11:25 am — GeekeryComments (0)

Rails script/performance/request needed a little help

While following another great Ryan Bates Railscast, I had a couple of problems on my Ubuntu 8.04 development machine:

  • Rails 2.1.0’s ActionController wants version 0.6.1 or later of the ruby-prof gem, but the usual gem repositories only have 0.6.0 now. I found suggestions to install Jeremy Kemper’s fork on Github, but though I’d added GitHub as a gem source, installing jeremy-ruby-prof didn’t work because that installed his version with that name, which didn’t help ActionController. What worked was:
    sudo gem uninstall jeremy-ruby-prof # be sure to uninstall old attempts!
    git clone git://github.com/jeremy/ruby-prof.git
    cd ruby-prof
    rake gem
    sudo gem install pkg/ruby-prof-0.6.1.gem
  • Then, script/performance/request ran, but generated several strange error messages instead of producing results:
    Couldnt get a file descriptor referring to the console
    Could not get a file descriptor referring to the console
    Couldnt get a file descriptor referring to the console
    Could not get a file descriptor referring to the console
    

    This turned out to be because script/performance/request wants to use ‘open’ to open its output files (a text file and an HTML document), but on Ubuntu, /usr/bin/open is a link to /usr/bin/openvt, which didn’t do what we want (and generated those error messages). I’m not sure what else uses ‘open’, but this did the right thing: it lets Firefox open the files:

    sudo ln -sf /usr/bin/firefox /usr/bin/open
10:29 am — GeekeryComments (2)

named_scope, joins, & includes

I used Rails 2.1’s named_scope to implement various ways to sort things on OsoEco. When I implemented “most discussed” on the Question model (questions have many comments), it involved joining in the comments table to count comments for each question. Initially, it looked something like:
named_scope :most_active, :joins => :comments, :group => "questions.id", order => "count(questions.id) desc"

That caused a problem, which the Pivotal Labs folks also commented on today:

When using named_scope, adding a :joins option will “mix-in” all of the attributes from that join table into your retrieved object, potentially overwriting any colliding attributes (including id … ouch!). There was consensus that this was a valuable feature, when used “properly”. Adding :select option can avoid this, or use :include.

Like they said, I fixed this with :select — the second try looked like this
named_scope :most_active, :select => "questions.*", :joins => :comments, :group => "questions.id", order => "count(questions.id) desc"

That worked (and fixed that problem), but it occurred to me that if my controller wanted to :include additional tables to add onto this scope (and that’s one of the cool things that named_scope enables), it wouldn’t work: Question.most_active.scoped(:include => :comments) raises a bad-SQL exception.

Fixing this required a bit of table aliasing, and led to this:
named_scope :most_active, :select => "questions.*", :joins => "left join comments as comments_for_count on comments_for_count.question_id = questions.id", :group => "questions.id", order => "count(questions.id) desc"

This worked, even with the :include added in a subsequent (anonymous) scope.

1:51 pm — GeekeryComments (1)

Hiding in plain sight

In writing my bio for Portland on Fire, I mentioned that I’d hidden my first name upside down in the “Read Me” file icon used on Macintosh during the late 1980’s: millions of people clicked on this icon to get help, and as far as I know, none of them noticed my name. The Wikipedia page for TeachText (the application I’d written which provides this icon) doesn’t mention this trivia (nor that I wrote it!).

After several years, TeachText was replaced by SimpleText, written by Tom Dowdy; Tom rightfully replaced my name with his; I’m just happy he kept the same style of icon. (I do rib Tom that TeachText was only 19K, where SimpleText was several times that in size.)

UPDATE: Sadly, I learned recently that Tom passed away. I’ll miss him: like many people I got to work with at Apple back then, he was smart and fun. I looked forward to seeing him every year at Apple’s developer conference, where we shared the distinction of being the only “Stump the Experts” experts who’d attended every session of that panel over the years.

1:43 pm — GeekeryComments (4)
Next Page »