-
Generating a plist file in rails
Posted on January 25th, 2010 1 commentI recently wrote an iPhone app (Waiting for approval in the app store at the time of writing) that needed data exported from a website (recyclinggroupfinder.com). The simplest way of handling external data in an app it seems is using a plist file, so I wrote this to generate one for me.
First of all I made my action respond to the plist format:
Next I created a builder file to format the data:
Then register the MIME type at the bottom of environment.rb:
Mime::Type.register "text/plist", :plistAnd that’s it! Well mostly. The XML file generated can be made significantly smaller by converting it into the binary plist format, run this on the command line in terminal after downloading the generated XML plist.
cat things_xml.plist | plutil -convert binary1 - -o things.plistThe resultant binary plist is almost half the size of the XML one, much better for inclusion in an iPhone app:
pleb:~ will$ ls -l things*
-rw-r--r-- 1 will will 1247300 20 Jan 18:50 things.plist
-rw-r--r--@ 1 will will 2110437 20 Jan 18:50 things_xml.plistOf course it would be much better to generate the binary format directly, and the plist-official gem looks like it can handle that and I mean to investigate, but I wrote the XML version before finding the gem, and it works for me!
-
Whenever a link on your website opens in a new window a panda cries
Posted on January 12th, 2010 1 commentYou’ve got a great website. It’s amazing. It’s so good no-one will want to leave it. Ever. Here’s what you’re thinking:
OMG wow. Our website is amazing. It’s so good no-one will want to leave it. Ever. Let’s help users enjoy our website forever by making all external links open in new windows so then they close the other websites our site will still be open. Our users will thank us until the end of time for making it easier to stay on our site, and anyway Marketing said we had to do it and they know the internet better than anyone!
Sad Panda
Oh dear. Most people don’t know this, but making external website links open in a new window makes pandas sad. Look, here’s a sad panda made sad because it used a website that opened external links in new windows.
You did that, with your new window link opening. (Panda by sholt).
Why Pandas cry
You need to consider that your website is going to be just one part of a users browsing session. The user will probably already have open tabs in their current browser window and the tab they have your website in will probably have history before your site. When you force a new window to open for a user you are interrupting their browsing flow. When this happens the user has a jarring user experience because of your website. Well done your website.
There are already controls in browsers to let users open links in new windows or tabs, in Safari they are the the first two options in the right-click context menu, or a Cmd+click:
When you force the user to open links from your website in a new window you are taking away control the user already has.
It’s a PITA and I have to work around it
Here’s what I personally do when your website opens a link in a new window:
- Your website forces new window to open when I click on a link.
- New window opens, I close it immediately.
- On your website again I Cmd+click the link or right click and select ‘open in new tab’.
- I close the tab your website was in and re-position the new tab with the new website in where the tab for your website used to be.
- I mentally remove one karma point from your website in my internal website excellence tracker.
Look at the amount of messing around your website made me do. And now, because of this messing around, your website is no-longer accessible via my browser back button. You’ve succeeded in making your website even less accessible, the exact opposite of that you were trying to achieve.
Luckily I’m mentally tough much like Chuck Norris and so can take this two, maybe three times before cracking, but Pandas aren’t as tough as me. If this happened to a panda the panda would just cry. Sad.
-
Freecycle and Freegle group location data as KML
Posted on December 29th, 2009 2 commentsIf you’ve got Google Earth (or something else that can read KML data) you might want to play around with the new recycling group location kml file I’ve put live on the Recycling Group Finder. More information here.
-
Optimising the Recycling Group Finder – Making a Ruby on Rails app faster
Posted on October 17th, 2009 No commentsThis is really just the ‘story’ of how I fixed a very slight performance issue with the Recycling Group Finder site that I run, but I figured it would be worth a post as an example or motivation to anyone else who needs to get started investigating their own Ruby on Rails app performance issues.
The performance problem
I’ve been very happy with the responsiveness of the Recycling Group Finder, so just out of interest, just to see what it would tell me, I installed the NewRelic RPM plugin and activated the free Bronze account available to EngineYard customers. The results were pretty satisfying as my average response time for the most popular page was 163ms maximum with the second most popular page at 90ms. Those are good response times and fall well within the 37signals response time rule:
Our general rule of thumb is that most pages should render their HTML on the server in less than 200ms and almost all in less than 500ms.
Suspicious looking
One of the great things about data visualisations is it can make it really easy to spot patterns. Take this New Relic graph for example:
The yellow on the graph represents time spent in the database, the blue is time spent in Ruby, ie. rendering, controllers etc. Memcached accesses are on there too but they’re so fast they hardly appear. This graph looked suspicious to me, I’d normally expect database time to be a much smaller proportion of the overall request time. So it looks like there may be some optimisation that can be done, but in order to optimise I first need to know what to optimise.
The hunt
Google for “rules of optimisation“. Most rules are something like this:
- Don’t optimise yet
- If you need to optimise, profile first.
I’m never going to be able to optimise my code unless I know what to optimise. If I trawl through looking for places that might be slow and trying to make them faster the chances are I’m going to spend hours changing code for no benefit. I might even make it slower. I need to know exactly where the bottleneck is, I need to profile my code.
There are a bunch of ways of finding out where your code is slow and I’ve personally used ruby-prof before with good results. However I know that the issue here is in the database, and I know that Rack::Bug will show me SQL queries that have run for an action, and importantly how long they took, so that’s what I’m going to try first. I install the plugin, configure it and load it up. The issue is immediately obvious:
Almost all of the SQL that is executed is under 0.5ms per query, there are a few queries at ~4ms but he one query that really stands out is the third one down. At 44.75ms it is more than half of the overall SQL time. Bingo! Now I know what is slow I need to know why it is slow. Time to break out the query analyser.
Fixing it
I needed to dig deeper into that SQL statement to see what it was doing, so I opened up a postgres shell and ran an
explain analyseon the query:The issue seems pretty clear. There is a Sequential scan on groups:
Seq Scan on groups (cost=0.00..626.75 rows=4885 width=363) (actual time=0.038..26.495 rows=5126 loops=1)A Sequential scan on a large table is going to sink performance. I can see that the sequential scan is definitely the issue in this case as the cost and time taken are significant proportions of the overall query time. I need to eliminate it. Here’s the code that generates that query:
@groups = Group.find(:all, :include => :group_page, :origin => [@location.lat, @location.lng], :limit => 30, :conditions => ["defunct = false AND lat is not null and lng is not null and full_address is not null and full_address != '' and country_code = ?", @location.country_code], :order => 'distance ASC, num_members DESC')I wrote this code ages ago and re-reading it now I can see that although I am limiting the returned results to 30 rows the query will have to hit every row in the table to determine which rows are in the returned 30 as there are no conditions to the query. Whoops. Looking over the Geokit docs I see there’s a
:withincondition so I added a:within => 100to the find. Testing the resultant query in the postgres shell usingexplain analyseagain and the query has dropped to 10ms. Not bad but it’s still using a sequential scan. Adding an index on the conditions speeds up the query further to ~1.2ms:Not bad when it started out at nearly 45ms. Here is the result reflected in the New Relic graph:
I deployed the new code approximately in the middle of the graph, it should be pretty obvious where.
Conclusion
Before you can optimise your Ruby on Rails app (or your app in any other framework/language for that matter) you need to know know where to optimise. Tools like Rack::Bug and NewRelic allow you to do this effectively and easily allowing you to direct your attention only on those parts of your app that need the attention.
On the Recycling Group Finder I cut response times drastically in about half an hour. Without knowing exactly where to make the change I would have been left guessing and may never have made the optimisation I did.
Programming, Rails, Ruby, Web, finder -
Looking for a Web-Development job? Learn Ruby and Ruby on Rails
Posted on October 12th, 2009 5 commentsSeriously. Not only will you be able to develop web-applications faster and with more joy, but if you fill some of the many Ruby on Rails job vacancies there are going the recruiters might stop bugging me so often.
There are Ruby on Rails jobs out there
Or that’s what is seems like from talking to people at the NWRUG and Geekup meetings I go to and by the phone calls I get from recruitment agents. I know of companies worried about using Ruby and Rails because of concerns over the number of developers available. These companies need you and they need you to write web applications for them in Ruby on Rails! These are companies who want to use Ruby on Rails and they will hire you if you learn it.
I’m fine sticking with $some_other_language but thanks anyway
That’s fine, there are lots of jobs available using your programming language. Well, maybe not if that language is Coldfusion. But if you expand your horizons, teach yourself something new and can prove to others that you’re interested in and capable of learning then you’re going to be a more valuable asset. That’s going to translate into more pay and a more fulfilling job using a language as expressive as Ruby and a framework as labor-saving as Ruby on Rails.
Worst case scenario is that you learn Ruby on Rails and you can write your own web-apps a whole lot faster (you do write your own web-apps right?), your CV looks better and you have more time for the dull stuff that you fit around programming. Watching Buffy or something. You know, programmer social life stuff.
I tried Ruby and Ruby on Rails already but I prefer Python…
Weirdo.
I tried Ruby and Ruby on Rails already but I prefer Cobol!
You don’t exist, go away.
You were thoroughly convincing, I’m sold
This post is so convincing that when I proof read it I nearly went and learned ruby on Rails myself, even though I already know it. If you want to you learn you can start here, and there’s going to be a local Ruby user in your area somewhere, sign up to their mailing list, we’re a pretty helpful bunch.
If you’re anywhere near Manchester, UK then come along to the next NWRUG meeting, it’s this Thursday and there’s free pizza. You need to sign up to attend.
Programming, Rails, Ruby, Web -
Protecting yourself against the WordPress login page exploit
Posted on August 11th, 2009 1 commentAnyone that runs a wordpress blog will hopefully be aware of the recent exploit against the login page:
“You can abuse the password reset function, and bypass the first step and
then reset the admin password…”and
“An attacker could exploit this vulnerability to compromise the admin
account of any wordpress/wordpress-mu <= 2.8.3″There’s no fix in any released version yet but you can protect yourself with a bit of Apache config until one is released. Just add this to your wordpress virtualhost replacing “you.re.ip.add” with the IP address you want to access the login page from:
<Location /wp-login.php>
Order deny,allow
Deny from all
Allow from you.re.ip.add
</Location>This will present any user not accessing your login page form that IP with a 403 Forbidden error. If you want to block all IPs until a fix comes out just miss out the Allow line:
<Location /wp-login.php>
Order deny,allow
Deny from all
</Location> -
Funpop.net launched
Posted on July 28th, 2009 1 commentI am happy to announce the launch of funpop.net, my new site. Funpop.net is a place to find cool or fun stuff from around the web. A 5 minute distraction for your coffee break or a place to find something to do at lunch.
Funpop.net started as the funpop twitter stream, I created the site to provide an archive of the tweets, and other features not available on Twitter such as tags and comments.
Tech
The site is build on Ruby on Rails and uses a PostgreSQL database as the back-end. It’s integrated with Twitter and features a Twitter based publishing system allowing content to be added to the site from Twitter itself. The site has an XML API should you want to use the information for your own purposes.
There are still features that need to be added and improvements to make so suggestions are welcome!
-
Blocking Internet Explorer 5.5
Posted on June 15th, 2009 2 commentsIE 5.5 is dead. The number of people using it are tiny, at least according to the stats on the most popular sites I run. Here are the numbers.
Jokes-o-matic
Has a larger proportion of Firefox users than Internet Explorer users due to the high level of traffic from some social bookmarking sites, meaning a more web-savvy crowd who are more likely to be using alternative browsers:

jokes-o-matic.com browser breakdown
The level of IE usage is still pretty high though, but even so only a single hit from IE 5.5 recently:

jokes-o-matic.com IE versions
Recycling Group Finder
A much more broad and ‘average’ user base with Internet Explorer dominant:

Recycling Group Finder browser breakdown
Still, only 6 Internet Explorer hits recently, a tiny proportion of overall visits:

Recycling Group Finder IE versions
What does this mean?

Yahoo.com as seen in Internet Explorer 5.5
These statistics, and others I have seen suggest that almost no-one uses Internet Explorer 5.5 or below any more. The small minority that do must be used to the internet breaking in unique and interesting ways due to the lack of support for more recent developments in CSS and really bad Javascript support (see right for yahoo.com as seen in Internet Explorer 5.5). I predict that a fair number of sites just don’t work in any usable way on anything less than Internet Explorer 6.
Time is money
Designing for multiple browsers takes time. The more browsers you need to support the more time you need to spend supporting them.
A recent project I worked on required a redesign of the site from the ground-up (aswell as a bunch of other stuff) and making the site work in any version of Internet Explorer lower than 6 just wasn’t worth the time, and therefore money, put into it. The return just wasn’t there and I decided that IE 5.5 was gone, dead, obsolete and I wasn’t going to try and mangle the design to work in it. Rather than just display a really crappy looking site to the user I decided I would let them know via a short and to-the-point message that their browser was not up to displaying the site and directing them to upgrade to a new version of their browser.
Give them the good news

Message displayed to all users visiting project in anything below IE 6
But how to do this? The site was developed in Ruby on Rails and I’d heard of a neat gem called rack-noie6 that provides a piece of Rack middleware that blocks Internet Explorer 6 and below, but that isn’t going to work in most cases. Hard as it may be to make your site look good in Internet Explorer 6 you can see from the stats above there’s still a large proportion of users using it and to turn them away would be crazy, at least while the pool of IE 6 users out there is still so large.
So a quick fork and patch later (github we <3 you so much) and the new noie6 was accepting an option for a minimum version of Internet Explorer it should accept instead of just rigidly blocking version 6 and below. Configuration is really simple:
Now any users visiting the site in anything below Internet Explorer 6 gets the message above helpfully directing them to update their browser. Not bad for a two line config update.
-
Google Groups now supported on the Recycling Group Finder
Posted on May 28th, 2009 No commentsI have just pushed live the latest feature of the Recycling Group Finder, support for Google Groups!
It has taken a while to roll out, the changes to the code-base that runs the site were pretty fundamental as the site was originally only written to work with Yahoo based groups. As a result there may be some issues, let me know if you see any.
To get started just email me your Google Groups recycling group URL or head over to the group addition page.
-
Jokes site gets pounded, again
Posted on April 1st, 2009 No commentsEvery once in a while I get whole load of incoming links from stumbleupon.com to my jokes site and it’s happened again with over 70,000 page views yesterday:
It’s rails site and only running on one mongrel, but there’s some pretty heavy cacheing in there so it olds up just fine. It’s a great feeling when you put a site up on the internet and you can actually see people using it.
And I realise that i’m publishing a post about a jokes site on April 1st, but this isn’t a joke!









