This Month
May 2007
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Year Archive
Login
User name:
Password:
Remember me 
View Article  Marching Bands and Camera Hate

Talks for today:

  • Morning keynote by Tim Bray.  Great talk about where "we" ought to be headed with Ruby and Rails.  Tim is proof that age and treachery can still beat youth and enthusiasm -- that makes me feel a lot better.
  • Another talk about using helpers in Rails to clean up views, this time by Glenn Vanderburg.  I guess I felt like the lesson didn't take the first time -- there wasn't too much overlap between this and the Thursday tutorial of nearly the same name, so no wasted time.
  • Joyent Slingshot -- a super-cool library that allows a Rails app to (with small modifications) run locally on a user's desktop, while still syncing with a remote data source.  Wow.  Writing a desktop app in Rails sounds like fun, I'll just have to think of a use for it.
  • Xen and the Art of Rails Deployment -- Ezra Z talked about the Xen virtualization framework, which allows you to turn one server into many "virtual servers."  To my shame, I haven't played with this stuff at all, so I was glad for the summary.  After seeing this and the Amazon EC2 presentation, I'm more convinced than ever that this is the way provisioning will happen in the very near future (<10 years for sure).  I don't kill my own chicken for Sunday dinner anymore, why should I provision my own server?
  • Practical Design for Developers -- A bit more high level than I was hoping for, but still plenty useful.  David Verba from AdaptivePath (the MeasureMap guys) talked briefly about information architecture, and how to design an application that people will actually use.  Isn't that what we all want?

Before lunch, attendees were treated to a short performance from the Extra Action Marching Band.  I'm from a somewhat funky town, but seeing a marching band complete with a platinum-wigged co-ed flag line reminded me that funky is a very relative term.  On a sad note, I had nearly 10 minutes of video showcasing the marching band but managed to corrupt / delete / burninate it while trying to pull it off my camera.  Oh well.

Tags:

View Article  Pictures, pictures

A few more pictures from yesterday are flying through the internets towards my photo stream as I type.  Thrill to the sight of... a dangerous chain of power strips.  I wasn't close enough to get a good shot of Ze Frank last night, but you can hit his site and get the general idea.  His discourse on graphic design and airplane safety cards was priceless.  I'll try to be more photophilic today (you know what I mean).

View Article  Rails After Dark

So it's almost 8:30PM on a Friday evening, and I am sitting in a darkened room waiting to see Ze Frank start his keynote.  That's my nightlife, baby!

[minutes pass...]

Talk has started. 

Ze Frank is better than Leno.

Why did this guy ever quit the show?

View Article  RailsConf 2007, Day 2

No midday update today, as I just didn't find the time to sit down in a quiet place.  Bits and pieces:

  • If you're going to put your company's website name on the back of a truck where it will be glanced at by passerby, it should be something easy to read -- i.e. something other than www.dogsdigit.net.  Let's just say I had to read it twice to get it right.
  • When you're the King of Web Frameworks, you can wear whatever the hell you want to.  I spotted DHH this afternoon after his keynote, and he was sporting testarossa red shoes.
  • Talk 1 this morning was on "Full-stack Web App Testing with Selenium and Rails."  Geek out!  This is a testing program that actually drives your web browser automatically, which makes it much better than forcing your kids to test your web app out (it doesn't cry or demand toys as payment).
  • Talk 2 was more of a product pitch, about using Amazon's EC2 service.  While it is an incredibly cool service, the "testimonial" did mention a few kinks yet to be worked out.  This is probably how we'll do all datacenter stuff in 10 years, and we'll wonder why we ever provisioned our own physical servers.
  • Talk 3 was from Rabble (I have to call him that because I heard another speaker address him that way in casual conversation) about going back and adding tests to your "legacy" Rails apps.  Legacy Rails apps.  I feel old already!  Basically he talked about how to reform your wayward programming practices and move toward proactive testing.
  • Talk 4 was probably my favorite, "Standing on the Shoulders of Giants" by Adam Keys.  Adam spoke about the value of reading source code written by others, especially code written by the "cool kids" of the Rails community.  This is an area I've meant to look into for awhile, but never got around to.  No more procrastination!  It looked like too much fun to miss.
  • The last time slot of the day didn't have anything of interest, so I took the MAX into downtown and headed for Mecca, aka Powell's City of Books.  I should have set an alarm on my phone or something, but I didn't and so I spent a little over an hour and a half happily browsing the stacks.  I almost bought the Bach and Beethoven action figures but couldn't figure out who would want them.

Now tomorrow, you may be in for a real treat: I have been invited to a bout of the local Roller Derby league, the Rose City Rollers.  Wait, what?  The story of how I got to this point is too long to type, so just hold your breath and wait to see if I actually make it to the derby.

Where are the pictures?  Well, I left my USB cable in the hotel room.  I'll have to post pix in the morning.  You'll just have to let my words paint a picture in your head for now.

Tags:

View Article  create vs. create! vs. new in Rails
I've been spending a little time lately on updating The Secret App to remove cruft (Login / User Engine being the two main sources of said cruft).  Now that I'm no longer locked into an old revision of edge, I have noticed that Rails's ActiveRecord behavior seems to have changed a bit.  Before, I could get away with saying
@widget = current_user.widgets.create!(params[:widget])
Now, that gets me a big fat nil in @widget.user_id.  Unfortunately,
@widget = current_user.widgets.new(params[:widget])
gives me the same darned thing.  The only way I could get the user_id to  fill properly was with
@widget = current_user.widgets.create(params[:widget])
Maybe it's something I am doing wrong, but I haven't found it yet.  I wouldn't put much effort into it, but I really like the clean syntax I get from #create! and so it has gotten under my skin.  Any ideas?  Anyone?  Bueller?
View Article  A small change to rails routing

A recent change in the way Rails deals with incoming requests caught me a bit off guard.  I was used to being all loosey-goosey with my routes, like saying

/categories/show/34-Detachable-Widgets.html

and having Rails happyily translate that into a request for /categories/show/34.  However, when I caught up to edge a few days ago, my tests started failing.  Wah?  Further investigation revealed that the culprit was that flagrant .html hanging there on the end (why? because I can).  After a bit of digging on the Rails mailing list, I finally found my buried treasure: a post by Jeremy Kemper mentioning that Rails now considers . a "URL separator."  Ergo, your route

:controller/:action/:id

becomes

:controller/:action/:id.:format

and all's right with the world again.  This allows us to force a format just by using it as the extension (i.e. trigger a specific response via responds_to), so I don't mind the change.  I just wish someone had mentioned it a bit more loudly... like I'm doing now.

Tags: ,

View Article  Good reference for RESTful Rails
I love a good cheat sheet; anything to condense a big ol' reference site into a page or so that I can flip to when I need it.  However, no one has made a good cheat sheet (or even a good reference, period) for the new RESTful Rails stuff.  The best one-post reference I've found is simply_restful in Rails Core on David Goodlad's blog.  Plenty of bloggers rah-rahed about simply_restful and gave a few examples of how to set it up, but David includes something unique: a table of all the auto-generated named routes and how to use them.  I swear, I must have spent half an hour looking for exactly that information.  Ah, sweet spoonfeeding!  Thanks again to Mr. Goodlad for putting that out there.
View Article  Raising well-behaved mongrels
Mongrel is the cool new thing in Rails deployment (even the main Rails site uses it now), but making it run well still requires some fussing and fiddling.  Two tips I recently ran across are worth mentioning:
  1. If you're using Pound (the best option until lighttpd's proxy support improves), you may want to adjust the TimeOut value therein.  It's really really short.
  2. If you're using MySQL, there is a mismatch between the interactive_timeout variable in MySQL server and the timeout Rails uses.  Add the line ActiveRecord::Base.verification_timeout = 14400
    to config/environment.rb to prevent... unpleasantness.
My mongrel installation is still having hiccups once a day or so, but these two tips together have improved its stability quite a bit.
View Article  RESTful tests

If you're drinking the latest flavor of Rails kool-aid, you are no doubt hard at work rewriting all of your controllers to conform to RESTful principles.  Good for you!  In your rush to coolness, however, don't forget to do the janitorial work of testing those great new actions.  I recently added Accept-based processing to one of my controller actions, and I wanted to test the XML response separately.  I couldn't figure out how to send the Accept: header in a test GET request for the life of me, until I stumbled upon Francois Beausoleil's post about respond_to order.  The simple answer:

@request.env['HTTP_ACCEPT'] = 'application/xml'

Stick that into your test method right before your get / post, and you should be good to go.

Tags: , , ,

View Article  Caring about URLs in your Rails app

If you're a Rails developer who wants users to actually visit your application once in awhile, it would help to pay some attention to the little white box at the top of your browser.  Right now, it probably says:

http://localhost:3000/bacon/show/31

While the URL appears clean to us programmer-types, there's plenty of room for improvement.  The main problem is that the ID, 31, has meaning only in the context of your application.  When the URL shows up somewhere else, it's just a number.  This matters a tiny bit to humans, and a lot more to search engines.  We'd like to put something there that tells what 31 actually is.  In my last app, my first attempt at URL beautification looked like this:

http://localhost:3000/bacon/show/Wood-Smoked

That's a good start: it loads the URL with more information about what's being displayed, and the dash as word separator is search engine friendly.  However, this setup still has problems:  what if two bacons have identical names?  This actually happened in my app, where several categories were named "General".  Also, what if we change the name of a bacon?  Then, references to the old name in the URL won't work.  That stinks!

I'll spare you the further thought exercise and say that someone else has already done the hard work for you.  His post on Transparent opaque changeable permanent URLs is a masterful dissection of both problem and solution.  In short, his solution is to put both the id AND the title / whatever into the "slug" (that thing at the end of the URL that we're concentrating on), and to redirect users if they get the ID right but use an old or incorrect title.  Sweet!  If you're like me, however, you wished for one more thing: spoonfed Rails code.  I found some of that, too, at URLs on Rails.  Finally, the author mentions implementation of the redirect for incorrect slugs but doesn't show the code.  He's right, it's easy, and here's how I did it:

@bacon = Bacon.find(params[:id])
if params[:id] != @bacon.to_param
  headers["Status"] = "301 Moved Permanently"
  redirect_to :id => @bacon and return
end

Now you should have all the code you need to build bulletproof, search engine-friendly URLs into your app.  Enjoy the bacon!

Tags:

View Article  My Very First Rails Patch
The other day, I ran into an odd problem with Rails migrations.  I needed to add an index to a MySQL TEXT column, and such indexes are required to include a prefix length (who knows why).  Anyway, I discovered that I couldn't just tack the prefix length onto the column name because ActiveRecord was blindly quoting the entire string.  I carped about it lightly on the #rails IRC channel, and forgot about it for a few weeks.  Today I decided to take a few minutes and see how hard it would be to fix that little wart.  Turns out it wasn't tough at all.  Behold my first [PATCH] ticket!  It's not exactly RJS, but hopefully someone will find it useful (and hopefully it won't break anything else).

Tags:
View Article  Eponym Directory Launch

Ah, finally!  Today I got the OK to announce what I've been working on for the past few months: The Eponym Blog Directory.  The directory, when filled, will contain the top blogs in several hundred nicely organized categories.  Blog rankings are determined by three factors: hotness, coolness, and freshness.  I could explain each factor in brain-crushing detail, but that would take away the magic -- and everyone likes magic, right?  The upshot is that if you know of a great blog that's authoritative in its niche (or if you run such a blog), you really ought to submit it.

If you like the look of the directory, I need to disclaim credit for that part up front.  John did a fantastic job on the site design.  The site would be a nicely programmed wart without his work.  As for the programming, much credit needs to go to the awesome folks on the Rails core team.  Their hard work has produced a framework that makes programming a joy (not surprising since that's in their mission statement).

Now it's back to the secret lab to start my next project...

Tags:

View Article  The Wicked Madness of acts_as_tree and :counter_cache

Alright, if you are a Rails wizard (the kind that wears a hat with moons and stars), you can safely ignore this post.

Still with me?  HA, tricked them!  Wizards may not know about this either, as I spent about 10 minutes googling and didn't come up with this info.  If you have a class that acts_as_tree and you want to use the :counter_cache option, you must follow a specific set of undocumented and illogical steps.  If you don't, here's what will happen:

  1.    
  2. If you just name the field children_count (which the docs seem to say you should do) and don't try to specify the cache field name, Rails will automatically look for widgets_count (assuming the table name is widgets).  Most of the posts I found in my research were from people who were painfully discovering this first fact.
  3.    
  4. If you then rename the field to widgets_count, you are STILL SCREWED. Your counts will indeed be updated when you add and remove children, but they won't actually be used in queries.  When you say Widget.find(1).children.size, Rails expects the cached count to be found in children_count.  Argh!

So, the solution is to say acts_as_tree :counter_cache => :children_count. My quick and unscientific tests (using script/console and watching development.log) confirmed to me that this caused the cache to be updated properly on creates, and used properly on queries. I supposed this could be considered a bug, so I may try and put it in a track ticket. At the least, it ought to be a note in the docs.

[Update: OK, so this was discussed several months ago on the trac.  Why hasn't someone put a handy note in the docs?]

Tags:

View Article  Cool Bits for Your Rails Toolkit

As I get deeper into my current project (a cool but still secret app built in Ruby on Rails), I'm starting to build up a good-sized toolchest of useful Ruby and Rails utilities.  I'm planning on summarizing the best in a future post (soon, honest) but I found one in particular today that deserves more attention.  As a former sysadmin, it warms the cockles of my heart to see an app like HeartBeat, offered by the hosting folks at Slingshot (note that you don't have to be a Slingshot customer to give Heartbeat a try).  Heartbeat is a simple web-based app monitor for your Rails app (I suppose it could monitor other apps), which also includes an innocent-looking module to let you run rake tasks via SSH.

Whoa.

Now, if you can write it as a rake task, you can run it from any web browser (and you can write anything as a rake task).  Two features seems a little light, but keep in mind that this was started as a Rails Day 2006 entry.  It's definitely a cool idea -- I'm already using it to monitor an app, so I'll follow up with my experiences.

Tags:

View Article  Give your Rails code some rcov love
Testing in Rails is a lot like 401(k) investing:  everybody talks about it, but few people actually follow through on it.  At least, that's my educated guess based on my own behavior.  I love having tests written, but figuring out exactly what to test and making the tests work can be exceedingly tedious (especially when you know that the code being tested works already).  I had heard of code coverage tools for awhile, but until I gave one a try I had no idea what they were capable of.  Enter rcov
This little gem (available as a gem, natch) looks over your tests and spits out a bundle of HTML showing you exactly what is and isn't being exercised by your tests.  In my case, it spits out a mostly red-highlighted copy of your source code (red is untested, and therefore bad).  From there, it's a matter of writing tests that at least exercise all of your untouched code.  You may not know (or be able to) throw down a lot of assertions, but simply exercising the method is a good start.
Please note that rcov isn't just for Rails -- it is a general Ruby tool, so your external libraries can benefit from it as well.  If you need that subconscious motivation to test that comes from seeing your source highlighted in red, be sure to give rcov a try.
View Article  bug in rails routing
If you're developing on Rails and keeping up with changes to branches/stable, you might have noticed a change that came through a few days ago to ActionPack.  This modification is supposed to prevent a recently discussed denial of service attack against Rails apps, but it has an unintended side effect as well.  As I quickly discovered, the change breaks routing to controllers in subdirectories (e.g. http://somesite/admin/foo/list).  I've posted a note to that effect on the trac ticket, but in the meantime there is a (dirty) workaround.  Simply define routes in config/routes.rb for each of your controllers that lives in a subdirectory:
map.connect 'foo/bar/:action', :controller => 'foo/bar'
map.connect 'foo/bar/:action/:id', :controller => 'foo/bar'
map.connect 'foo/blah/:action/:id', :controller => 'foo/blah'
map.connect 'foo/blah/:action/:id', :controller => 'foo/blah'
This gets routing going again for me, and it's an acceptable compromise until the core folks can fix the glitch.

tags:
View Article  Don't skimp on your dates
Rails has a plethora of nifty and useful helpers for making your views look beautiful.  However, the one weak spot (to me at least) is the handling of date inputs.  A few frameworks make it easier to input dates naturally (i.e. just type 'tomorrow') and there are several nice javascript-based choosers out there.  In fine Rails tradition, someone has taken these two great tastes and made them taste great together.  Witness the DateBox Engine.  Seriously, this blows away the default rails date_select output.  If you're accepting dates from your users, please don't torture them with three dropdowns anymore -- it's very unRails.

Tags:rails

View Article  I'm a winner!
Things have definitely been falling my way this week!  After our turbo house sale last weekend, this morning I find out that I won a copy of Micro ISV: From Vision To Reality by Bob Walsh (blog, blog).  I've had my eye on the book for a month or so to read/buy, so I guess this cinches the deal.

The giveaway was done by PerlCast and Apress to promote their interview with Mr. Walsh, so thanks to them as well.  I solemnly swear to read the whole darn thing and write about it here.

Tags:microISV

View Article  Mock objects and testing in Rails
As I have been developing Rails apps over the past few months, one area I have still been neglecting is tests.  I know that tests are fun and delicious, and that they will make me more attractive to members of the opposite sex.  Don't get me wrong -- I have written a small suite of tests and they have helped in keeping stuff from breaking in secret.  However, I haven't turned into the total testing nerd that some people seem to be.  The other obstacle to really revving up on tests was that I was always running into external dependencies that would screw up or slow down my tests.  To top it off, the feature in Rails that's supposed to alleviate this problem (mock objects) is only lightly documented.  A perfect recipe for slacking!

Finally, the other day while trying to fix a problem The Right Way I decided to dig into the web and find out how to use those infernal mock objects.  Turns out there's not much to it.  One thing to note is that if you're mocking one of your own objects, you'll want to follow this thread and note the poster's self-solution.  I did that to remove some of the external dependencies in my models, and it worked like a champ.  I ended up spending several hours building, breaking, and fixing tests.  It's sort of like mowing the lawn -- sweaty and repetitive, but worth the effort for the great-looking results.
View Article  Spreadsheet + Web 2.0 = WikiCalc
Back in the day, one of the first computer applications I ever learned to use was VisiCalc on a TRS-80 Model III.  Written by Dan Bricklin, this "electronic spreadsheet" application has been widely credited with kick-starting the first Personal Computer boom of the late 70s and early 80s.  I think we can agree that Dan is The Man.

Now comes the news that Dan has been hard at work on yet another potentially BIG project: WikiCalc.  Imagine a spreadsheet that works in a  web browser and can link to other such spreadsheets anywhere on the web (much as you'd link two regular spreadsheets together in a formula).  To quote the site, "[wikiCalc]  is a web authoring tool for pages that include data that is more than just unformatted prose."

Dan seems to be addressing a fundamental weakness of most current wikis: no rich handling of structured data.  They're great for capturing and organizing text, but have you tried making even simple tables in them?  No fun.  I hope Dan's onto something -- it wouldn't be the first time he shook things up.

Tags: , , ,

View Article  Rails: Storing Money reliably
I do love Rails, but when it comes to handling money you have to treat it like a small child -- that is, don't expect precision accounting.  Rounding errors and other vagaries of fixed-precision floating-point arithmetic have given programmers gray hairs for some time -- I can remember a particular rounding error in Perl that bit me several years ago.  Maybe it's just dynamically typed languages, but they seem to have a very laissez-faire attitude when it comes to making sure you get exactly the number you should.
Forewarned is forearmed, and I had read that Rails (Ruby) would need some  handholding in this area as well.  I read a little bit about the Money library but that seemed like overkill (I don't need to track multiple currencies yet).  I figured that the easiest way out was to store the amount as an integer number of cents in the database and then fiddle with the assignment and accessor methods to make it go in and come out correctly.  5 minutes later, I had this:

def foo=(foo)
    self[:foo] = foo.to_f * 100.0
end

def foo
     self[:foo] / 100.0
end


What looks simple actually took a few tries to get right.  Initially, I couldn't figure out how to set the attribute without calling the setter method (which I was writing), thus attempting to harness The Spaceballs Effect where you're watching the movie as it's being made.  I eventually did all the wrong ways and found the right way to directly access the attributes.  Again, total time here was about 10 minutes.  The odd part is that I haven't seen this written up anywhere else -- maybe everyone else just writes it in their sleep.
View Article  Windows vs. Subversion: fight!
I'm appparently uncovering every way in which you can screw up your Windows-based development platform.  After previously delving into the arcana of Windows and file modes, today I decided to do something smart for a change, and let someone else do my work.  I needed user authentication for a project I'm developing in Rails, so I grabbed the Login Engine.  Well, to be more precise, I <em>attempted</em> to grab said engine.  My attempts to start the party by installing the Engines plugin were answered by the following koan:<br/>
<code>
svn: 'C:' is not a working copy
</code><br/>
Try googling that, I dare you.  Know what you'll get back?  Almost nothing.  While I am fully aware that the root directory of my drive isn't a working copy of a subversion project, I'm not sure what that has to do with checking out a Rails plugin.  After a bit of fiddling, I did what any sensible developer would do:  I cheated.  I committed the project under Windows, checked it out on my Mac, and installed the plugins faster than you can say, "Guy Kawasaki."  Another round of Subversion and I was back where I started, with plugins firmly in place.  Moral of the story?  If what you have doesn't Just Work, find something that does.
View Article  Ruby nested arrays: a recursive descent into madness

I've spent the past little while wrestling with what seems to be inconsistent behavior in Ruby's Array class. I fully accept that the problem is almost certainly EBCAK, but it still doesn't make sense. Take the following snippet of Ruby code:

 FOX_SIZES = [  
["Smallish", "small"],
["Not so wee", "medium"],
["Frighteningly large", "large"]
].freeze

So this gives us a nice nested array suitable for building a select form element and other fun stuff. Now take a look at this:FOX_SIZES.each {|sizearray| p sizearray.first }This does what you'd expect, giving you the first elements of the three inner arrays on three lines. Next, let's say you're a Rails developer (and a green one at that) and you wanted to output that list in your template:

Valid sizes: <%= FOX_SIZES.each {|sizearray| p sizearray.first } %>

Bzzt! You'll get the following nastiness back in your template:

Smallish small Not so wee medium Frighteningly large large

Not quite what we wanted. The problem is that while the iterator works fine, it doesn't actually capture and return the stuff you're printing. You could probably get that kind of effect with Enumerable#inject, but that seemed like overkill to me. I finally settled for adding the following helper method to my controller's helper file:

module BaconHelper
def valid_sizes_string
valid_sizes = []
Fox::FOX_SIZES.each {|sizearray| valid_sizes << sizearray.first }
valid_sizes.join(", ")
end
end

This assumes that your little sizes array lives in your Fox model. I've shown you how to do the list, but I haven't really talked about the inconsistency part.  Try this:

FOX_SIZES.grep(" ")

You'd expect this to iterate (recursively) over the array, giving you each element that contains spaces.  Wouldn't that be cool?  Unfortunately, the grep method comes  from the Enumerable mix-in, and therefore it behaves differently than each.  In the 5 minutes it takes you to figure this out, you may experience some cognitive dissonance or feelings of paranoia.  Simply tell yourself that your computer is not making fun of you, and the differing lineage of the two methods explains their divergent behavior.

The irony here is that I'm not using the data in a select element anymore, so I could have converted it to a hash about an hour ago and forgotten this whole incident. That doesn't sound like nearly so much fun. 

So remember, kids: be careful with those methods!  You don't know where they came from!

View Article  Love the Rails! Hate the Rails!
OK, so it’s 11PM and I should be asleep so I can hit my day early tomorrow. Instead, I’m banging my head against what is undoubtedly a simple error in the Rails app I’ve elected to take on. No internet access means I’m limited to my rails mailing list archive for help. Argh. NoMethodError, how could you treat me so wrong? I gave you my evening, all you gave me was a nil object!

Update: several hours and 5 cranial bruises later, the problem appears to have cleared itself up. The skinny is that if you have a model with a has_many relationship and you represent that with a list, the list really should be initialized when the (parent) object is instantiated. That way when you go to use << you don’t get a painful surprise upside the head.