Posted by Larry Karnowski
Mon, 02 Feb 2009 23:14:00 GMT
Since upgrading to Rails 2.2, you might be seeing lots of messages like this:
config.gem: Unpacked gem blah-1.0.0 in vendor/gems
has no specification file. Run 'rake gems:refresh_specs' to fix this.
Running 'rake gems:refresh_specs" takes care of most of these, and upgrading any remaining gems will usually take care of the rest. But it seems like most of the projects I'm on still have one or three home-grown, really old, or really odd gems that just don't have specs. I should write specs for these, I know. So I let Rails complain... but...
But now, months later, I'm realizing there are just a few gems I'm never going to upgrade. And I'm seeing these messages... A LOT. Every time I run a test in TextMate. Every time I run tests from rake. Every time I run almost any rake task, period. It's driving me MAD!
So, if you've been a good boy or girl and taken care of most your gems, and a few are still hanging around, here's the magic to make those messages go away:
In your config/environment.rb file:
# Bootstrap the Rails environment, frameworks, and default configuration
require File.join(File.dirname(__FILE__), 'boot')
# Add this line at your own risk!
Rails::VendorGemSourceIndex.silence_spec_warnings = true
Rails::Initializer.run do |config|
Tags config, hack, rails, ruby, rubygems | 4 comments
Posted by Larry Karnowski
Sat, 31 Jan 2009 19:42:00 GMT
I've been quietly hacking away on integrating three great tools:
- Screw.Unit, a wonderful RSpec-like JavaScript testing framework
- env.js, a wonderful fake JavaScript DOM implementation
- Ruby on Rails plugins
What does that get me? Voila! Easy headless and in-browser testing of my unobtrusive JavaScript! (For more information on Screw.Unit, I also created a mailing list with the original authors' permission.)
Tags bdd, javascript, plugin, rails, tdd, testing, env.js, screw.unit | 1 comment
Posted by Larry Karnowski
Fri, 24 Oct 2008 19:39:00 GMT
Say you're doing some drag or drag-and-drop operation in Javascript, and you notice that wherever the user drags, the underlying text or other elements are being highlighted. This can obscure what the user is doing, and it just generally feels "wrong." How do you turn that off?
Here's two quick techniques, one for Firefox and another for Internet Explorer & Safari. (Actually, this is IE7. I haven't tested in IE6.)
Firefox
This one is a CSS fix. Just add the following to your stylesheet and then add the "no-selection" class to whatever you're going to drag over.
.no-selection { -moz-user-select: none; }
Internet Explorer & Safari
We have to use Javascript for this one. Call disable when you start your drag behavior, and then re-enable when the drag is complete. Note that calling this function will disable all text selection until you re-enable, so be careful.
// This works for Safari & IE7, and it is safely ignored in Firefox. You'll have
// to add a "-moz-user-select:none;" to whatever you don't want selected in Firefox.
function enableDocumentSelection(enable) {
if(enable) {
document.onselectstart = _original_onselectstart;
}
else {
_original_onselectstart = document.onselectstart;
document.onselectstart = function() { return false; }
}
}
Tags javascript | no comments
Posted by Larry Karnowski
Fri, 10 Oct 2008 14:07:00 GMT
I'm flying to Ann Arbor, Michigan later today to give my "Usability on Rails" talk at the Great Lakes Ruby Bash tomorrow. If you're attending, please drop me a note (as I don't know a soul that'll be there). I'll also be hanging out on IRC in #glrb and #midwest.rb. I'm hoping to meet some new friends and convince some geeks of the wonderful ways of "teh us4b1l1t13z"!
Tags bash, conference, great, lakes, on, rails, ruby, usability | no comments
Posted by Larry Karnowski
Thu, 04 Sep 2008 13:37:00 GMT
- Connect your iPhone and let it sync.
- Before you disconnect, run the "Image Capture" utility. It lives in your computer's "Applications" directory.
- Go to the menu, click "Image Capture", then "Preferences".
- On the "Image Capture Preferences" window, change the "When a camera is connected, open:" setting to "No application".
- Close the "Image Capture" application.
- Voila! No more iPhoto launching automatically.
However, be aware that this will stop iPhoto from launching when you connect any digital camera. If you want to pull photos from a camera, you'll have to manually launch iPhoto and hit the "import" button. Snatch!
Tags iphone, iphoto, tips | 4 comments
Posted by Larry Karnowski
Fri, 29 Aug 2008 15:00:00 GMT
If you're using Rails' alias_method_chain mechanism, please make sure that your new method always takes a block and passes that block up the chain, even if you don't need the block yourself. Consider this being a good "alias_method_chain" neighbor. Here's why -- if you don't, no one who comes along behind you can add a block to the chain. You've effectively "block-blocked" them.
Here's an example. I wanted to add some functionality to Rails' error_messages_for method. Specifically, I wanted to be able to pass a block to it that implemented a tiny DSL for massaging the errors output before passing them up the chain to the normal error_messages_for functionality. I implemented this by adding an alias_method_chain layer on top of the error_messages_for.
In my tests this worked fine, but when I put it in my actual Rails project, the method just stopped working. It took me a while to find that another developer on the project was also alias_method_chaining the error_messages_for, but was not taking a block, and thus not passing it up the chain. In effect, he was dropping my block on the floor. No good.
So here's the template you should follow when creating an alias_method_chain:
def method_with_something_cool(arg1, arg2, &block)
... your custom pre-chain code ...
method_without_something_cool(arg1, arg2, &block)
... your custom post-chain code ...
end
alias_method_chain :method, :something_cool
Call the old method with a block even if the old method never took a block! Don't be a cock-blocker! Err.... block-blocker!
Tags alias_method_chain, blocks, rails, ruby | 1 comment
Posted by Larry Karnowski
Mon, 21 Jul 2008 00:22:00 GMT
Here are some important lessons I learned about accurately copying MP3s (or really any kind of file) from a Linux ext3 filesystem to an external USB hard-drive using FAT32.
When mounting the USB hard drive, be sure to use iocharset=utf8 in your mount options. (To be safest, I put this in my /etc/fstab so I won't forget it.) Otherwise you will have problems creating directories or files that have European or Asian characters in their names. I had some real problems with all the Mexican, Celtic, and Yako Kanno albums I own. Rsync will just flat out refuse to create them without this option. (And forget the Icelandic heavy metal. It's right out.)
Similarly, when mounting, you might want to include the "shortname=mixed" mount option too. Although I personally didn't have a big problem with this, several posts I read online mentioned that rsync might try to upload a file multiple times. The issue is that since FAT32 stores both a short-name (remember the 8.3 names?) and a long-name, the filesystem can get confused occasionally. Again, I didn't see this myself. I used the option, though, with no trouble.
Lastly, don't use the standard "rsync -a" (archive) flag. It tries to maintain user and group ownership, and FAT32 doesn't support either so you get a lot of "chown NO PERMISSION" errors, etc. Basically, you're making rsync do more work than it has to. Similarly, the "-a" option also tries to preserve symlinks which FAT32 doesn't support. I'm not really sure what would happen in that case, probably more warnings. Instead use "rsync -rt" to recurse through each subdirectory and to maintain the file's last modified time. That's about all FAT32 will let you do!
Hope this helps! Keep rockin'!
Tags backup, external, fat32, linux, mp3, rsync, usb, utf8 | 2 comments
Posted by Larry Karnowski
Tue, 10 Jun 2008 12:30:00 GMT
While doing a "git svn rebase", if you have merge conflicts here are some things to remember:
- While doing a rebase, if anything bad happens, you end up on a "(no-branch)" branch.
- When doing a "git status", you'll see a ".dotest" file in your working directory. Just ignore it.
- If you want to bail, do a "git rebase --abort". (Note there is no "git svn rebase --abort".)
- Fix the merge conflict file manually, then do a "git add [file]".
- Next do a "git rebase --continue". (Note there's no "svn" version of this either.)
- If it complains about "did you forget to call 'git add'?", then evidently your edit turned the conflict into a no-op change. Do a "git rebase --skip" to skip it. (Very weird, but true.)
- Rinse and repeat until the lather is gone, your scalp silky smooth, and the rebase is complete. At any time you can "git rebase --abort" to bail.
What happened to me? Well, I didn't realize what was going on, continued to work on the "not a branch" branch, commited changes, even dcommited changes back to Subversion. It was ugly, but not insurmountable. A buddy clued me into the "not a branch" situation, I was able to get back to my real branch and resurrect my code. It took a few "git rebase --continue" commands, and a tense moment around a "git rebase --skip", but now everything's hunky dory.
This very odd email really helped me a lot. You might be interested at some point.
Tags git | 6 comments
Posted by Larry Karnowski
Thu, 29 May 2008 15:43:00 GMT
Today I'm attending my first RailsConf and coincidentally my first conference as a Relevance employee. Let me tell you, Relevance does conferences differently than anywhere else I've worked. I'll argue that they do them right.
First off, we put 80% of the company on one plane yesterday. (Hmm, okay, maybe that was a little scary.) We took up several rows on the plane, and we definitely made an impression on the passengers and staff. Several rows of geeks all sitting with MacBook Pros passing airplane power cords up and down the rows was a sight to see! Much hacking got done, for sure.
Secondly, pretty much the entire company is giving a tutorial together later this afternoon. Technically, the talk is being given by the company's founders, Stu Halloway and Justin Gehtland, and two of the principals, Rob Sanheim and Jason Rudolph, but in reality we're all pitching in. The session itself is a bit different -- it's a hands-on walk-through of how to approach a Ruby open source project and contribute. It's metric-tool heavy and really gives your average Ruby/Rails programmer a firm grasp of how to take a four hour coding session and turn it into useful patches for a real open source project. It's one of the most innovative and interesting tutorials I've seen in my several years as an open source guy, and I'm proud to be a part of it.
I hope y'all will stop by our tutorial today if you're in the conference. If you can't make it, be sure to stop one of the Relevance guys to say hello. You'll see us in our "think relevance" t-shirts all up and down the halls. Relevance is all-in at RailsConf.
no comments
Posted by Larry Karnowski
Fri, 23 May 2008 15:30:00 GMT
Your webapp user needs to download a file, but you don't know the exact size of this file ahead of time. So what do you send as the content-length? Is an incorrect content-length okay? Do you even need a content-length? The Internet is pretty silent on the subject.
For example, my webapp users want to download several files as one zip file, but I don't want to create the zip file ahead of time just to know the content-length. I'd rather create the zip file on the fly and stream it to the user a chunk at a time, as it's created. This saves me time, process memory, code to clean up temporary zip files, etc. However, the problem here is -- how big will this zip file be? What do I send as the content-length?
More importantly, what does content length really do? Is it important? What happens if you don't set it?
Effects of Content Length
- The web browser will NOT read more bytes than the content-length value. If you accidentally set your content-length too low, the download is halted prematurely and the downloaded file will most likely be corrupt. Do NOT set it too low. This is the only case where content-length can really hurt you.
- If the content-length is set the web browser will show a progress bar while downloading. This is a very important usability feature for medium and large files, and you really want it. You want your user to know how far along they are, so they don't cancel the download and start it over, or worse just abandon your site.
- If the content-length is not set, then the user gets an "Unknown Size" message while downloading, and they won't get a progress bar. Avoid this if possible, but it is sometimes okay for very small files that get downloaded so fast the user won't care they didn't see a progress bar. (Still, you want to avoid this.)
- If you set the content-length to zero (usually only by accident), then your web browser will usually gleefully say they downloaded the file successfully, and save a zero-length empty file. Do not set the content length to zero.
The Reverse Bob Barker Rule
That first effect is the most important: Don't set the content-length too low, or your users will suffer corrupted files. So this brings us to the reverse-Bob-Barker rule.
"Get as close to the real content-length as possible without going UNDER."
Why Not Go WAY Over?
Okay, so we know not to go under, but why not just go way over? Why not, for example, just double our estimated size? Well, nothing terrible will happen. The browser will keep trying to read content, and when the server says "no more," the browser will safely finish the file and say done, even if it thought there was more content coming.
The only negative is that you want the user to get the best download experience possible. So if you guessed your content-length to be 100 MB, but the real download is actually 50 MB, the user will see a progress bar showing they are 50% of the way done, with probably another minute to download, and then suddenly the browser goes from 50% to 100%, from one minute left to done! The user will be confused.
We call this the "Goldilocks Effect" in usability. In this case, the porridge was too hot -- the user will be left wondering why the download dramatically sped up at the last minute. Did the file download successfully? Did the download really fail but the browser didn't tell us? Although nothing bad actually happened, the user is still left with a sense of unease. We definitely want to avoid this.
How Close is Close Enough?
So, all this boils down to:
If you don't know the exact content-length ahead of time, determine a good cheating algorithm and pad for safety.
But how much padding do you need? How much is enough? What's too much? My experience is this:
Aim for a padding of 1%.
Here's my scale:
- Padding over 10% is so inaccurate that the user won't believe the progress bar. "We jumped from 90% to done immediately? Is this thing broken? Is my file corrupt?"
- Padding of between 3% to 10% is less fantastic, but still pretty bad.
- Padding of between 1% and 3% is the best you can expect in most cases. Depending on the size of the file, the download percentage usually jumps in 2-5% increments anyway. This is only unacceptable for the largest of files, where web browsers are showing download percentages in 1% increments. (And even there this is sometimes the best you can do.)
- Padding under 1% is a bit dangerous unless you have a lot of confidence in your guessing algorithm. Remember, the only way to really lose here is to guess under the real content-length.
So this brings us to 1% padding. In most cases, this should be fairly easy to predict, and the web browser will show a 99% to 100% download progress, which is what the user wants to see anyway.
Where Does This Work?
I've tested this "extra content-length" technique on the following platforms, all with success:
- Internet Explorer 6 on Windows XP (on VMWare on my Mac)
- Internet Explorer 7 on Windows XP (on VMWare on my Mac)
- Firefox 2 on Macintosh
- Firefox 3 RC1 on Macintosh
- Safari 3.1.1
4 comments