Posts
-
Testing Custom Rails Validations with Shoulda
In this post, I’ll show how to write custom validations for Rails’ models, and how to test them with Shoulda, the ‘Makes tests easy on the fingers and the eyes’ testing plugin.
Rails’ ActiveRecord validations are great when you want to make sure attributes are the way you want them. But what about the use-cases where you need to write a custom one?
Creating the Validation
The validation we’ll write is called
validates_positive_or_zero
, which will return an error if a relevant integer attribute is negative.Create the file
RAILS_ROOT/lib/validations.rb
with the following contents:def validates_positive_or_zero(*attr_names) # Set the default error message. configuration = { :message => "Cannot be negative" } # Set a custom error message if there is one. configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash) # Check none of the object's attributes are negative. validates_each attr_names do |obj, atr, val| obj.errors.add(atr, configuration[:message]) if val
Note: This particular validation is complementary to
validates_numericality_of
, you’ll get some odd failures if you don’t use it.We need to
require
this file before we can use the new validation in our model:class Badger 'no-one is that light' end
The first
validates_positive_or_zero
validates two attributes at once, whereas the second validates only one attribute with a custom error message.Testing the Validation
I feel I should give a little introduction to Shoulda, it’s one of those tools that leaves me wondering how I ever managed before. Despite the popularity of RSpec within the Ruby community, I’m not a fan, it’s just too verbose, which I find gets in the way (it doesn’t render views though, which makes functional testing a lot easier, this feature for standard Rails tests please!). Shoulda is the answer for those of us who want standard Rails tests, but with them being neater and tidier. I encourage you to check it out more fully, but for this example, I’ll stay on-subject.
For our custom validation we could test it in the regular fashion with a test_foo method, or we could write a custom method that we could use again and again without re-writing the same code. The latter is the approach we are going to take here, with the method being in the style of the other shoulda validation tests.
First up, install the Shoulda plugin:
./script/plugin install git://github.com/thoughtbot/shoulda.git
Next, create the file
RAILS_ROOT/test/shoulda_macros/validations.rb
with the following contents:class Test::Unit::TestCase def self.should_only_allow_positive_or_zero_values_for(*attributes) configuration = { :message => "Cannot be negative" } configuration.update(attributes.pop) if attributes.last.is_a?(Hash) klass = model_class attributes.each do |attribute| attribute = attribute.to_sym should "only allow positive or zero values for #{attribute}" do assert_bad_value(klass, attribute, -1, configuration[:message]) end end end private # Taken from the shoulda private methods def model_class self.name.gsub(/Test$/, '').constantize end end
Now we set up our tests in
RAILS_ROOT/test/units/badger_test.rb
:require 'test_helper' class BadgerTest 'no-one is that light' end
And we’re done! I hope this was useful for you.
-
GitHub Bookmarklet Updated
I’ve added support for Github’s repository search and making use of their new search to Github Bookmarklet.
Get it
Drag this to your bookmarks bar: Github Search.
Repository Search
As for user and code-search, but use the r: prefix. You can also use any of the GitHub macros as defined in the blog post linked from above.
r: will_paginateDocs etc
-
2008 in Review
Just like I did for 2007 and 2006, I bring you my review of the year, in the form of one of those annoying round-robin email type question things. Yeah!.
1. What did you do in 2008 that you’d never done before?
Learned to drive.2. Did you keep your new years’ resolutions, and will you make more for next year?
Didn’t make any this year. Next year’s will be to properly beast it on the bike.3. Did anyone close to you give birth?
Not that I noticed.4. Did anyone close to you die?
Nope.5. What countries did you visit?
France, Spain, Ireland, Holland and Malaysia.6. What would you like to have in 2009 that you lacked in 2008?
No knee injuries, no big crashes.7. What date(s) from 2008 will remain etched upon your memory, and why?
22 August; passed my driving test (1st attempt, 1 minor).
14th July; seeing the Tour de France on Hautacam.8. What was your biggest achievement of the year?
Learning to drive (this will get old).
My three (minor) race wins deserve a mention too.9. What was your biggest failure?
My second knee injury, killed my season after only three races. Crashing the week before Drumlanrig, and not racing due to recovery.10. Did you suffer illness or injury?
See above.11. What was the best thing you bought?
Another year with a lot of purchases; possibly the new TV or my SIDs.12. Whose behavior merited celebration?
Mine… learning to drive snore13. Whose behavior made you appalled and depressed?
Royal Mail, again. Oh, and the RBS business team for being slooow.14. Where did most of your money go?
Bikes.15. What did you get really, really, really excited about?
Driving.16. What song will always remind you of 2008?
Barry Louis Polisar – All I Want Is You17. Compared to this time last year, are you:
i. happier or sadder? Happier.
ii. thinner or fatter? The same, as always!
iii. richer or poorer? Richer.18. What do you wish you’d done more of?
Racing.19. What do you wish you’d done less of?
Not riding.20. How did you spend Christmas?
Mum’s for Christmas day, Dad’s for Boxing day.21. Who did you spend the most time on the phone with?
Clients, nailing down specs for work. Again.22. Did you fall in love in 2008?
Yeah, she ’s lovely. :o) Again!23. How many one night stands in this last year?
That’s a bit rude! But since you ask, none. Again, woo!24. What was your favorite TV program?
The Big Bang Theory.25. Do you hate anyone now that you didn’t hate this time last year?
Nah, I’m pretty mellow with everyone. Same again.26. What was the new best book you read?
The Rider – Tim Krabbe and Sam Garrett.27. What was your greatest musical discovery?
The Juno Soundtrack.28. What did you want and get?
A TV, a new race frame. A Magnus dog.29. What did you want and not get?
A badger. I did see a fair few though.30. What was your favorite new film of this year?
No Country for Old Men.31. What did you do on your birthday, and how old were you?
I was 23, and I have no idea what I did.32. What one thing would have made your year immeasurably more satisfying?
A badger.33. How would you describe your personal fashion concept in 2008?
It was the closest thing to hand when I wanted to put clothes on. Same as last year.34. What kept you sane?
The bike. Same as last year.35. Which celebrity/public figure did you fancy the most?
Um………none come to mind. Again.36. What political issue stirred you the most?
That the long-term unemployed are finally getting a boot in the backside.37. Who did you miss?
Umm…38. Who was the best new person you met?
Kamal, what a coding legend.39. Tell us a valuable life lesson you learned in 2008:
Take an umbrella.40. Quote a song lyric that sums up your year:
“I got soul but I’m not a soldier” -
Wheel Review: Stans ZTR Olympic Rim / American Classic Hubs
Getting them
July 2007, it was new wheels time. I still thought that Hope hubs and Mavic rims were some of the best wheels going, but they were a little porky considering my lack of bulk. So, Stans ZTR Olympic rims seemed to be a good option to drop some weight; I didn’t really fancy building rims without eyelets onto Hope hubs with their notoriously uneven spoke tension. So, built wheels from Just Riding Along using American Classic hubs was the way to go.
I had several emails back and forth with Jon from JRA, regarding spare spokes, and whether to go with DT Revolutions or the slightly stronger DT Super Comp. I went with Revolutions, seeing as all my other wheels were built with them and I hadn’t had any issues.
Without spending insane amounts of money, these wheels are some of the lightest going, especially when you consider that Mavic’s top end wheels are almost twice the price, and 150g heavier.
First Ride
Hard test, their first ride was 10 at Kirroughtree, five hours of rocky punishment. I ran a Maxxis Crossmark on the back, and one of my favourites, an IRC Mibro on the front. All went well, the wheels felt super fast, accelerating out of corners and maneuverability in tight spaces were awesome.
Going Tubeless
OK, so this is one of the best things about these wheels, tubeless usage becomes so easy. I was going for the adventurous option, using just Stan’s yellow spoke tape (no rimstrip) and a pair of non-tubeless and super-light Crossmark eXCeption tyres. It took about 30 minutes and a lot of compressed air to get the tyres on, but boy was the end result light!
Second Ride
Another bit of a test, a 7-day stage race in Poland and the Czech Republic. It was pretty rocky, which twice resulted in me tearing the tyres. Thankfully standard tyres mean that popping them off the bead and throwing a tube in is super easy. Not being near a compressor did mean I couldn’t inflate the tyres, but even so, some of the euros were totally blown away with how light the wheels were with tubes in.
Better Tubeless
For 2008 I decided to use rimstrips to make mounting tyres easier. I still need to use the compressor (proper tubeless tyres make do with just a track pump), but it takes about 30s. This does incur a minor weight penalty, and you do have to remove a rimstrip when you puncture, but it’s worth it to get the tyres on easily.
Servicing
The hubs do have a tiny bit of tension adjustment in them, to allow take-up on play that develops, but this only works so far. After 14 months I replaced all four bearings in the rear wheel. These are tiny, 22mm outer diameter, with a 17mm inner diameter, so they don’t feel as smooth as bigger bearings in the likes of a Hope or DT hub. The replacement itself is a doddle, taking about 10 minutes including cleaning and re-greasing the freewheel mechanism.
The rims have for the most part remained true, although the front rim has developed about 3mm of lateral buckle, something which could easily be trued out of them. I believe that due to their construction, their strength is far superior to heavier offerings from DT and Mavic.
Overall
I love these wheels. Apart from my minor niggles with the size of the bearings in the rear wheel (JRA and other suppliers offer many hub options), they are fantastic race or trail wheels. I’ve given them a total battering and they’ve more or less only lost some of their shine. Customer service from JRA has been supreme, and they’re backed up by the fantastic folks at Paligap. Go get some!
-
Rails Plugin: Acts As Follower
Followers are the new friends. Apps such as Twitter and Github have effectively enabled virtual stalking within their apps. So how can you do this easily without wasting time with your own join tables? Acts_As_Follower to the rescue!
Install
./script/plugin install git://github.com/tcocca/acts_as_follower.git
Usage
A service like Twitter would have a
user
model, which would be both a follower and followable…class User < ActiveRecord::Base acts_as_follower acts_as_followable end # In the console... user1.follow(user2) # Get the users following user2 user2.followers # => # Array containing user1 # Get the users user1 is following user1.following # => Array containing user2 # Check following user1.following?(user2) # => true user2.following?(user1) # => false # Stop following user1.stop_following(user2)
Acts_As_Follower allows heterogeneous follow relationships too, so a user could follow repositories and users, say, in an application like Github.
This plugin saved me a lot of time during the start-up of a recent project, and it hopefully should do the same for you. For more usage examples, see the README.
-
Watching 'Cross
Yesterday I hopped down to Peebles to watch the fifth round of the Scottish Cyclo-Cross Series. It was nice to be a spectator for a change, even though it looked like great fun. I forgot my camera, and had Magnus (the dog) with me, so photographs were iPhone only, and thus not high-quality enough for posting loads of them.
The course was a cracker, and certainly lived up to the ‘Euro-style’ billing. Lots of muddy grass, steep run-ups following hurdles, more steep bits, and some super slippy off-camber descents.
Kenta Gallagher got off to a mega start, pulling out a fair gap on a chasing group of Iain Nimmo (Squatra Porcini), James Fraser-Moodie (Pedal Power) and Rab Wardell (Sandy Wallace Cycles). Around the fourth lap the chasing group was split up when Moodie decided to go off on his own, Nimmo dropped back a few seconds with Wardell a few seconds further back.
On lap six Moodie bridged up to Gallagher and pulled away on his own. He went on to take the win with about a 30s gap to Gallagher. Nimmo was in third, with Andy Wardman taking fourth.
Maybe I’ll do ’cross next year. Maybe.
-
GitHub Bookmarklet Now Supports Code Search
I’ve added support for Github’s new code-search feature to Github Bookmarklet.
Get it
Drag this to your bookmarks bar: Github Search.
Code Search
As for user-search, but use the c: prefix. You can also use any of the GitHub macros as defined on the code-search page
c: badger language:rubyDocs etc
-
Broken Comments
It has come to my attention that a change to my comments system made two months ago didn’t go so well.
I had intended for all spam comments to be deleted immediately. This was happening, but a bug caused all good comments to be saved, but marked as spam.
Fixed now. Apologies to all those affected, I’ll reply as soon as I can.
-
Announcing GitHub Bookmarklet
You have to love GitHub! Just last week I was saying to Kamal on the phone that I now instinctively search for a project on GitHub before Google, because it’s likely to be there, and grabbing a copy or just browsing the source is made so easy for me.
What a shame it’s an extra few clicks to search it. Until now! Enter the GitHub Bookmarlet!
Install
Save the following link as a bookmark, or drag it to the links/bookmarks bar in your browser:
If you get stuck, Delicous have a lovely guide to bookmarklet installation.
Usage
When you click on the bookmarklet, it’ll give you a text prompt. Type in the name of the project you want to search for, and hit return. You’ll be taken to the GitHub search page for your query.
Hitting ESC or Cancel leaves your browser in it’s previous state.
User Macro
Want to search for a user? Type in ‘u:’ followed by your query. So for instance to look at Kamal’s github account, I would type in:
u:kamal
.Hitting Return or OK now takes you straight to the user’s Github profile, or shows you a 404 if there is no such user.
Code Search
As for user-search, but use the c: prefix. You can also use any of the GitHub macros as defined on the code-search page: http://github.com/codesearch.
c: badger language:ruby
.Acknowledgements
- John Gruber for his bookmarklet formatting script.
- The GitHub team for, well, Github.
Future
If you have any suggestions, send me a message on GitHub, or fork the project and throw me a pull-request once you’ve made your changes.
-
There is one Man
Despite not riding cyclo-cross this season, I’m still hooked on it! I wait impatiently for coverage of the Scottish CX series, as much as the World Cups and Superprestige (Watch these live online) rounds.
When it comes to the bigger events, there is one man I’m sure we all idolize, Sven Nys! He’s a tower of power in a ’cross race, and no slouch on a mountainbike either, scoring a 9th place at the Olympics this year.
Sit back and enjoy this awesome compilation of his greatest moments from last year, especially around 35seconds where he’s pumping his arm while running up some stairs.