After banging my head against a wall wondering why certain image uploads would silently fail, while others succeeded, I stumbled across a file_column bug (and yes, I reported it).
If you have the following in your model:
validates_file_format_of :image, :in => ["bmp", "gif", "jpg", "pdf", "png"]
And you upload a file with one of these extensions in a different case, for example “SAMPLE.JPG”, the file format validation fails.
Workaround (non-DRY): add case variations, like this:
validates_file_format_of :image, :in => ["bmp", "gif", "jpg", "pdf", "png", "BMP", "GIF", "JPG", "PDF", "PNG"]
Grr.
One of Internet Explorer’s famous shortcomings is its lack of native support for transparency in PNG images—one of the very characteristic that makes PNGs so appealing to begin with. Here’s how to incorporate transparent PNGs into your site in a way that all browsers will handle, using only Cascading Style Sheets (CSS).
1) The Approach
We’re going to put each image into the document twice: once in a way that Internet Explorer will understand, and once in a way that standards-compliant browsers can understand. In both cases, we’re going to use an appropriately classed <div> element:
<div class="png_standard<img src="my_graphic.png" width="150" height="294"></div>
<div class=”png_ie” style=”width=150; height=294; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=’my_graphic.png’, sizingMethod=’scale’);”></div>
This results in one image and an empty <div> showing up for Firefox and Safari, and two images (the first without transparency) showing up in IE. Note that you must specify the height and width of the image in the style tag of the png_ie <div>!
2) The Following Line is True. The Preceding Line is False.
Now we’re going to use CSS selectors to only show the <div> that’s appropriate for the browser. It’s crucial that these CSS rules are included in your style sheet in the order presented!
We’re going to take advantage of a non-standard CSS selector that only IE recognizes: * html.
div.png_standard {display: block;}
div.png-ie {display: none;}
* html div.png_standard {display: none;}
* html div.png_ie {display: block;}
Read from top to bottom, these rules state:
- Display any <div> with class=”png_standard” in the normal way.
- Do not display any <div> with class=”png_ie”
- If you are IE and can read this, hide any <div> with class=”png_standard”
- If you are IE and can read this, show any <div> with class=”png_ie”
3) The Last Step
Actually, there is no last step That’s it! For standards-compliant browsers, the <div> containing the transparent PNG is displayed normally, and the <div> containing the ugly IE code is hidden away. For IE, the <div> that it does not understand remains hidden, and it renders the <div> that forces it to recognize PNG transparency.
Transparent PNG in Internet Explorer for Windows:
And in Safari for Mac OS X:
4) Sample Code
Assuming that you have a PNG named my_image.png, the following page will render appropriately in all browsers:
<html>
<head>
<style type="text/css">
div.png_standard {display: block;}
div.png-ie {display: none;}
* html div.png_standard {display: none;}
* html div.png_ie {display: block;}
body { background-color: #bdbdce; }
</style>
</head>
<body>
<div class="png_standard"><img src="my_graphic.png" width="150" height="294"></div>
<div class="png_ie" style="width=150; height=294; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
src='my_graphic.png', sizingMethod='scale');"></div>
</body>
</html>
I’ve got Tip of the Day enabled in TextMate. Check out this gem from today…
-25 points if you don’t get the reference.
While implementing Sur Max’s excellent Simple Captcha plugin, I ran into a very frustrating issue. No matter what was entered, the valid_with_captcha? method always returned false.
After some digging I finally realized that there was a conflict with restful_authentication. The resolution is simple, luckily. You just need to add the following to your user controller:
attr_accessible :captcha, :captcha_key
That did it for me! Hopefully this will help someone else as well.
From the description for Acts As Enterprisey:
Rails make life easy for us but– and it’s a big but– we don’t want it to look easy. acts_as_enterprisey is your friend. How does acts_as_enterprisey make webapp development look hard? Well, the only way your client can judge your app is by playing around with it. What better gives the feeling of heavy weights being lifted behind the scenes than slow response times? Exactly. That’s what acts_as_enterprisey does.
Simply insert acts_as_enterprisey in your ActiveRecord model [and set the delay to whatever value you want.] So while your client clicks, …waits…, and then gets the page, you can blather on heroically about wrestling with clustered indexes, cache expiration strategies, n log n seek times, etc ad nauseam.
Clients pay you to solve their technical problems. They want to feel like they’re getting their money’s worth. Especially after you start submitting enterprisey invoices.
So make their wishes come true: it’s only fair. Ethical, even. Crank the delay up as the deadline approaches, make them sweat, display fortitude and perseverance, etc. And when they can’t take it (the app’s sluggishness, your bills, whatever) any more, [remove] acts_as_enterprisey from your models and book the flights to Vegas.
This is akin to the infamous “make_it_go_faster” flag. Yay.
One of the goals that I set for myself for the year was to spend more time playing guitar. I’ve been playing on and off for over 10 years now, but last year was particularly hectic with work and Europe and I barely picked up an instrument at all. So a few weeks ago I went to pick up new strings. I had noticed a new guitar shop, Danche Guitars, in Oak Park and decided to pop in and check it out.
When I stepped in, I was immediately transported back in time. The smell of wood glue, sawdust, and fine wood reminded me of the harpsichord workshop of Peter Redstone, an old neighbor from Virginia.
I was charmed by the shop and the proprietor, an older Croatian gentleman who evidently took tremendous pride in the workmanship of his luxury guitars. He was even nice enough to let me play one of them, but I have to admit that the $15,000 price tag of the guitar I was holding made me more than a little nervous.
After half an hour of talking, as I was selecting my strings, he pointed to a flyer on the wall and said that his son was taking students if I was interested in signing up for lessons. I should point out that while I take tremendous pride in being self-taught in nearly everything that I do, I had realized some time ago that there were fundamental flaws in my physical approach to the guitar, and these were preventing me from doing certain things that I needed to do. So I swallowed my pride and gave him my name and number.
Now, every week, I’m studying under the patient tutelage of the incredibly talented Goran Ivanovic, and I’m seeing tremendous progress in a very short time.
By the way, if you’re interested in hearing some of my music, I recently uploaded some songs to Last.fm. Just look for “Dust and a Shadow“.
I’m currently working on a project to create a travel website, and I needed to have a bunch of member profiles to use for testing the member directory. I came across a great Ruby gem called Faker which I’ve used to create the dummy accounts.
Installation is easy, of course: gem install Faker
Next, I created a Rake task for populating the accounts:
namespace :db do
namespace :development do
desc "Create user records in the development database."
task :fake_user_data => :environment do
require 'faker'
@countries = ["United States", "Canada", "United Kingdom", "Germany", "Mexico"]
@genders = ["Male","Female"]
@privacy = ["members", "public"]
def randomDate(params={})
years_back = params[:year_range] || 5
latest_year = params [:year_latest] || 0
year = (rand * (years_back)).ceil + (Time.now.year - latest_year - years_back)
month = (rand * 12).ceil
day = (rand * 31).ceil
series = [date = Time.local(year, month, day)]
if params[:series]
params[:series].each do |some_time_after|
series << series.last + (rand * some_time_after).ceil
end
return series
end
date
end
100.times do
u = User.new(
:first_name => Faker::Name.first_name,
:last_name => Faker::Name.last_name,
:birthdate => randomDate(:year_range => 60, :year_latest => 22),
:created_at => randomDate(:year_range => 4, :year_latest => 0),
:city => Faker::Lorem.words(1).to_s.capitalize,
:state => Faker::Address.us_state(),
:country => @countries.rand.to_s,
:password => “greatpasswordhuh”,
:password_confirmation => “greatpasswordhuh”,
:accepts_terms_and_conditions => true,
:gender => @genders.rand.to_s,
:email => Faker::Internet.email
)
u.extended_profile = ExtendedProfile.new(
:bio => Faker::Lorem.sentences(5).join(” “),
:occupation => Faker::Lorem.words(1).to_s.capitalize
)
u.preferences = Preferences.new()
u.save!
end
end
end
end
Note that while Faker was good for creating random names, e-mail addresses, etc., I needed some other data that was outside of its scope, for example gender and country. For these, I simply created an array (like @genders = ["Male","Female"]) and called @genders.rand to pick a value. I also used its Lorem Ipsum generator to create random city names, occupations, and biographical text.
Once the Rake task was written, it was simply a matter of typing rake db:development:fake_user_data to populate the database with my junk records. Pretty sweet!
You can find Faker at http://faker.rubyforge.org/.
I finally finished migrating everything over from my old desktop to my new iMac. (I’m still amazed that a consumer-level Mac is more than twice as fast as my old high-end desktop… such is the pace of hardware, of course.)
At any rate, when I started working on one of my Rails projects, I was surprised to see that performance was really poor– much slower that on the old box. Then I realized that my Ruby and Rails installations probably got migrated by Migration Assistant.
Sure enough, ruby -v in Terminal revealed Ruby 1.8.6 for PowerPC/Darwin. This means that Ruby is running in PPC emulation, which explains the performance I was seeing.
Since Leopard ships with Ruby, this means that I now have two versions: in /usr/bin/ruby there’s the version that came with the OS, which is
ruby 1.8.6 (2007-06-07 patchlevel 36) [universal-darwin9.0]
In /usr/local/bin/ruby there’s:
ruby 1.8.6 (2007-03-13 patchlevel 0) [powerpc-darwin8.10.0].
This is obviously a problem…
Some Google time later, I came across this post on Punctuated Productivity; that set me in the right direction for uninstalling the old version and getting the new one up to snuff. His approach was to completely wipe /usr/local/bin and /opt/, which I found a little scary. Here’s a slightly more surgical approach.
- Remove the following from /usr/local/bin (sudo, of course):
gem*
update_rubygems
rails
rake
mongrel-rails
cap
capify
gpgen
index_gem_repository.rb
libpng-config
- Unfortunately, I had just installed and configured ImageMagick on the old box, which is a long and tricky process that I’ll have to do all over again. But since it was the only thing that I had installed on that day, so I was able to
open ./ to open /usr/local/bin in the Finder, sort by date, and select/delete all of the ImageMagick and RMagick files in a couple of clicks:
Magick-config
Wand-config
animate
compare
composite
conjure
convert
display
freetype-config
identify
import
libpng12-config
libwmf-config
libwmf-fontmap
mogrify
montage
pkg-config
stream
wmf2eps
wmf2fig
wmf2gd
wmf2svg
wmf2x
libpng-config
- My last uninstall step was to delete /opt after all, because only MacPorts (which I used to install ImageMagick) had put anything in there.
Now hash -r followed by which ruby correctly reveals /usr/bin/ruby, and ruby -v reports ruby 1.8.6 (2007-06-07 patchlevel 36) [universal-darwin9.0]
Now to reinstall Rails:
sudo gem install rails --include-dependencies
Next I have to reinstall ImageMagick and RMagick, which will hopefully be less painful this time around now that I know about MacPorts…

Take a look at Tuesday: from 49 to -2 in about 8 hours. Whee!
Hard to believe, but my 20th high school reunion is coming up next year. This fact doesn’t make me feel “old” or anything, though; I simply don’t feel like I’m the same person. At all. And while I can certainly narrate the steps that led me from a town of 400 in the swamps of Virginia to where I am now, it seems more like a familiar fiction than memory. Odd.
The organizers of the reunion are using some sort of pre-packaged high school reunion web app, where you invite your classmates to register and everyone can see profiles, send mail, etc. I was particularly happy to see the name of one of my long-lost school friends, Leon, appear in the roster.
He probably doesn’t realize it, but he’s the reason that I did so well in high school. I was in danger of being bored out of my mind, unchallenged and unmotivated by the curriculum. But Leon and I had an unspoken competition for who could get the best grades in our science, computer lit, and math classes. Usually, the gap between us came down to tenths of a point. This was particularly true in our honors physics class, where we essentially taught ourselves.
Leon and I were also protogeeks, both of us having a natural affinity for programming. We had plans to start our own software company (”Z-Tech”) and signed up for every free subscription, swag, and sample that we could, under our company name. We worked side-by-side on the state-of-the-art Apple ][e computers that were in the lab, and probably drove our computer lit teacher crazy. We laughed over the old Beagle Bros. catalogs, shared secrets for cracking copy-protected software, and took secret pleasure in crashing the computers of our fellow students when they got too annoying.
I am also eternally grateful for the time that Leon loaned me his programmable Tandy scientific calculator, which allowed me to conduct one of my earliest experiments in parapsychology for the science fair. (That’s a story for another post.)
I’ve thought about Leon from time to time over the years, wondering what he ended up doing, and if the path of his life ever went the way he expected it to. Unfortunately, his last name is just common enough to make him Google-proof. But I’m happy to say that almost immediately after I registered on the reunion site, I got an e-mail from him, reminiscing about the old days. I can’t wait to catch up with him.
Leon, do you still have any of those old 5.25″ floppies around?
|
No Comments »