Wednesday, 27 November 2013

Link: loading-icon generator

Load info is a neat website that lets you generate your own loading icon.

The first page has a hypnotising array of load-icons to choose. Click on one and it'll bring up a box that lets you choose the size and colours you want and it'll generate you a customised animated gif you can use.

Tuesday, 19 November 2013

Thursday, 14 November 2013

Zen and the Art of Western Rationality

Zen seems to have, as central to its dogma, a mystery tradition. ie it makes all its teachings appear incredibly mysterious in what appears to be an effort to make it seem harder to attain - and thus weed out those not willing to work for the enlightenment it proffers.

at least this is how it seems to western thinking. I've known a number of people who have fallen into what I believe is the trap of thinking that zen actually *is* a mysterious hidden secret that can only be approached in a non-rational way...

The reality is that zen is a very good way of switching off that part of the mind that gets in the way of thinking about the things that zen teaches... however, its not the only way.

As they say in zen - zen is not the way, but it approaches the way.

ie it's a good way of starting out, but it won't get you all the way there.

and (unlike the smugness of certain woo-woo types would lead you to believe) it's not the *only* way of reaching The Way.

It's my contention that it is just as possible to work your way there, starting with traditional western rationality/philosophy.

Here's an example pulled from zen:

A teacher once said "this is my short staff. If I call it a short staff, I deny its reality, but if I do not call it a short staff, I deny its fact, so what do I call it?"

It sounds incredibly mysterious. It's a mind-puzzle that you must work out for yourself - and if you are starting from scratch, it may take years of meditation to get to an answer... or you may grasp it in a second.

This is why it seems mysterious, like a great hidden secret that must be very valuable and thus you can feel all smug about knowing...

However, this koan contains some truths which are quite easily expressed in Western rationality also, and I believe it's more valuable to share those truths than to remain "terribly mysterious".


This koan, to me, expresses the map vs territory problem.

The map is not the territory, and yet it is the territory - just not *all* of the territory. The territory is represented by the map, but it is not defined by the map. Change the map (say, pencil in a new road) and the territory will not change (the new road does not spontaneously appear). Change the territory, and the map must be changed to match or lose it's connection with the territory.

Yet the map (if properly drawn) is the territory also - that road connects to this one in just such a way. If you follow the pattern of roads on the map, you will arrive at the destination that the map says you will.

The territory contains those facts that are within the map, but it *is not* the map itself. The map contains facts which are defined in the territory. You can recognise the territory by looking at the map - but the territory is so much more. It contains trees and roof-tiles and many other things that are not in the map.

The map is not the territory, and the territory is not the map

If I look at a map of england and say that this is england I will deny the reality of england. But if I look at the map and say that it is not england, then I deny the fact that the map is of england.

The map is the territory and is not the territory

but using the map you can approach the territory, but it is not the territory.

It does and does not have "england-nature"...


To get back to the koan... the object that the teacher is holding out is a short staff - that is the fact. If he said "this is not a short staff" then he would be denying the fact of it actually being a good example of a short staff.

However - if he broke it in half (so that it was no longer a short staff), it wouldn't be like there was no longer any short staves in the world. Thus you cannot say that is is "the" short staff. Other short staves are not defined by the properties of the object in the teacher's hand.

The name "short staff" is just a reference to it... but not a definitive one. It is not the same short staff as, say another one lying on the floor over there. If I can point to each and say "this is a short staff" then you are not naming a thing, only categorising it.

Therefore if you name it "short staff" you deny the reality of it being something *more* than a short staff.

The phrase "short staff" is the map that lets us recognise "things that have the short-staff property"... but it is not the short staff itself.

Now - perhaps you got something different from the short-staff koan. If so, instead of being "all zen and mysterious" about it, I implore you to figure out what it is you've learned... and share it with the rest of us.

Thursday, 7 November 2013

Link: Awesome guides to building a functional rails app

Rails girls is a group dedicated to training up the next generation of Rails developers... who happen to be women.

They tend to run over a weekend and get women of all backgrounds (but without rails experience) to build a rails app from scratch.

They have a set of materials that is brief, but quite impressive - and if you follow them through step-by-step it's a quick tutorial on how to get a pretty decently functional Rails app off the ground.

Start with the App tutorial to get it up and running with a simple scaffold, to add some basic styling with bootstrap, and add picture-uploads with carrierwave.

Then follow the set of guides (links are at the bottom of the app-tutorial page) to get it up on heroku, to add authentication with devise, to use geocoding to add your widgets to a map, to create thumbnails for your uploaded images and more.

With just the above you can get a fairly decent rails app built for most purposes in a day or so.

Friday, 1 November 2013

Putting your heroku repo on github

When I set up a new quick-and-dirty app on heroku... I often also want to put my code up on github.

I was really surprised this simple process wasn't covered in the otherwise pretty excellent Getting started with Rails 4 post on heroku.

It's pretty straightforward, so here it is.

If you follow the instructions as per the getting started guide (above), you'll have a local git repo, and it'll be tracking the heroku remote as "heroku". which means there's no problem with using the bog standard "origin" for your github repo version.

So from there

Step 1 create a new repo on github

  1. Go to your github page eg this is the github page for me: taryneast's github
  2. Click on the "repositories" tab
  3. Click the green "new" button
  4. Give it a name and, optionally, a description
  5. Click "create repository"

Step 2 - link it to your heroku app

  1. Go to your heroku app's settings page. this will be something like: https://dashboard.heroku.com/apps/<myapp>/settings
  2. About halfway down you can add your repo-name. It'll be <mygitusername>/<mygitrepo>
  3. Click save

Step 3 - link your local repo to the github remote

  1. open a terminal in your rails app's root directory
  2. type git remote add origin git@github.com:<mygitusername>/<mygitrepo>.git
  3. git push -u origin master

Your heroku app is now on github.

You can continue to push to heroku with:
git push heroku master
and to github with:
git push origin master

Wednesday, 16 October 2013

Levelling up in Ruby/Rails - for free.

So, I've recently found myself back on the job market... at least I will be, but I first want to re-sharpen my skills. I've been working in legacy Rails for a while now, and I want to make sure I'm au fait with the latest and greatest the ruby+rails world has to offer.

But when I went looking for courses - there's not a lot on offer for experienced rails devs. Most rails courses are pitched at complete beginners wanting to become a rails dev. Fair enough, but what can I do to polish my existing skills?

Thankfully, some more digging produced a nice set of related online tutorials and screencasts that will get me ship-shape in no time, and for far less than I expected

NewRelic CodeSchool offer

NewRelic currently has an offer whereby if you deploy a new site with NewRelic installed, you can get a free month of CodeSchool. Now, NewRelic is an awesomely useful tool for giving you extremely useful metrics for your site. They even have a free account - and to set this all up, you can roll out a simple site to heroku (also for free) with the new_relic gem installed and away you go.

You can then sign up for a free CodeSchool account (which will give you access to the basic level free courses), and sometime in the near future - you'll get an email from NewRelic with a special promotion code to give you your free month at CodeSchool.

CodeSchool = Rails for Zombies!

So once you've got a month of code school - you can start to work your way through the courses. Starting with the simple "Try ruby" course and through their funny "Rails for Zombies" courses all the way through Rails testing and best practices and some advanced topics of Ruby.

I was happy to discover that even in the simplest ruby course there was one or two things I'd never seen before - so they're all worth the time (but you can skip ahead to the challenges if they're too simple for you).

But the courses don't just cover Ruby/Rails, they also have a series for Javascript, HTML5, CSS3 and even iOS development. Which I'll be availing myself of for the next month - and will almost certainly spring for longer until I've done them all!

From zombies to RailsCasts

I was even happier to discover, that as a "prize" for finishing the "Rails for zombies 2" course, you get one month of a Railscasts Pro account.

Now RailsCasts was where I was planning on heading next anyway - I followed RailsCasts religiously in my early years of developing Rails, and learned a hell of a lot thereby. The number of screencasts that Ryan Bates has done by now is simply staggering. They cover a huge range of topics from detailed aspects of developing Rails (eg tagging or nested forms), to most of the commonly-used tools, and it's great place to go if you want help on a particular topic. To get access to a free month of these on a pro account is wonderful icing on top of the CodeSchool month.

Other CodeSchool courses give you other freebies, and discounts on books etc too, along with lots of links to other amazingly useful resources - so my reading list has suffered a cambrian-explosion this week. I'll keep you tuned if I dig out any further fabulous free offers.


Update: you can now get 3 months of code school for free

It's a limited offer... here's a link: 3 months of codeschool

Saturday, 5 October 2013

Putting a price on your technical debt

Ben Orenstein has written an interesting article: How much should global variables cost?.

It's basically a price-list for different kinds of technical debt, and you can use it to calculate the "cost" that each of your commits adds to your codebase. By actually putting a dollar amount on each "violation" - you can get a good, visceral feel for what you're doing.

As he points out - you can still choose whether or not to keep something (sometimes you really do need to do something that would otherwise be considered a no-no), as long as you can "afford" it.

I think it's an interesting way of looking at the problem. I'd like to see you regaining points for fixing/refactoring similar code-violations out of the project too :)

Saturday, 28 September 2013

Link: don't publish your secret keys on github

I probably don't really need to tell you that it's dangerous to publish secret keys on a public website... but which key am I talking about here?

  # this one...
  MyApp::Application.config.secret_key_base = 'fb636477f014943b9cf2d202f9da4349a580fbb9521ef38d8dc0111ae933a10bfec732ce7d563a854db1663ba00af1db21d06d6764d84a88d0a6286bcd2299e2'

It's one of those things that often gets overlooked...

  rails new
  git add .
  git push

Bam!

But if you're on heroku, rather than deploying to your own hosted site (where you can easily drop config files into a shared directory), how do you have a secret key?

Here's a great little gist that will show you how to set it up on an environment variable.


Update/gotcha

Don't forget, that if you put more than one of these into your .env file... you need to append to the file or you just overwrote your secret key (oops)


Further update

If you're on heroku and putting one of these environment variables into code that will be evaluated at compile-time (eg config/initializers/devise.rb for instance) you will need to switch on heroku's "compile time environment variable" option: user-env-compile or you will not even be able to deploy your site.

This feature allows your environment variables to be available during compilation of the slug (which is when things like bundler, asset-compilation etc are run)

Note that this is an experimental heroku:labs feature - so blah blah use at your own risk blah...

Friday, 16 August 2013

Gotcha: irb, multi-line strings and "Display all 309 possibilities? (y or n)"

Small thing I figured out. I was in irb and trying to copy/paste some text into a multi-line string to play with gsub, and it kept exploding halfway through and showing the message:

Display all 309 possibilities? (y or n)

instead of actually allowing me to create a multi-line string.

Turns out, irb still responds to tab-completion even if you're halfway through creating a multi-line string.

This kinda sucks if you want a string that contains tabs - but don't want to manually type the whole string (including tabs) yourself as you go along.

To fix it, I copy/pasted the text into vim and used :retab to replace the tabs with spaces before copying it back into the string in irb... its a hack, but it worked for my purposes.

Any thoughts on a better solution?

Wednesday, 7 August 2013

Link: alias vs alias_method

If you ever wondered what the difference was, this quick post by Neeraj Singh will show you the difference between alias and alias_method

TL;DR:

  • alias_method is slightly more flexible accepting strings or symbols
  • alias_method will redefine local methods at runtime - which means you can override the aliased method in a subclass and alias_method will pick this up
  • alias will keep the original scope when aliasing - so even if you override the method in a subclass, the aliased method will refer to the parent's original method
  • alias works nicer with rdoc

Don't forget to use a comma for alias_method

Tuesday, 30 July 2013

Link: ruby-warrior : a fun way to learn a little ruby

I just came across ruby-warrior.

I can thoroughly recommend it as a couple of hours of fun diversion while picking up a few lines of basic ruby.

Its byline is:

"A triumphant quest of adventure, love & destiny all within a few lines of code."

Tuesday, 23 July 2013

Link: Your boss, the invader from Mars (or how agile transitions can become unhinged by poor buy-in)

If you've ever tried to implement an agile transition in a traditional workplace, you'll know there are many stumbling blocks - one of the greatest being that of the existing stakeholder: Your boss, the invader from Mars explains how change can and should be dealt with by both the SCRUM and kanban approaches to agile development - and how that can easily be messed up by your boss.

The case-study especially strikes a chord with my experiences, describing a shop wanting to "become more agile" but not actually implementing agile processes, instead trying to add the "agile" on top - with a rather apt simile where the agile process are described as "layered over existing dysfunctions as a sort of veneer".

The article then goes on to show various ways in which a boss who is not fully vested in the agile approach can unhinge the transition process... but also lets us learn the various lessons from that so a we can hopefully improve upon it in our own attempts.

Thursday, 18 July 2013

Gotcha: rvm and No binary rubies available for: ubuntu/12.04/x86_64/ruby-1.8.7

I'm working with a legacy rails system. We're still stuck on Rails 2.3.2 (yes really) and ruby 1.8.7 (it's better than 1.8.6 which we were on only a few months back).

I've just been given a new computer at work (finally) and it has ubuntu 12.04 - and I was trying to set it up with a rails stack. For which I can strongly recommend Ryan Bigg's howto article: Ubuntu, Ruby, RVM, Rails, and You

I got through the tutorial ok, happily installed ruby 1.9.3... but when I tried to install 1.8.7, I hit a snag.

    triton:[~]% rvm install 1.8.7
    Searching for binary rubies, this might take some time.
    No binary rubies available for: ubuntu/12.04/x86_64/ruby-1.8.7-p374.
    Continuing with compilation. Please read 'rvm help mount' to get more information on binary rubies.
    You requested building with 'gcc-4.4' but it is not in your path.

According to rvm, you can list the set of available rubies using rvm remote which gave me:

    # Rubies available for 'ubuntu/12.04/x86_64':
    
       ruby-1.9.3-p194
       ruby-1.9.3-p286
       ruby-1.9.3-p327
       ruby-1.9.3-p362
       ruby-1.9.3-p374
       ruby-1.9.3-p392
       ruby-1.9.3-p429
       ruby-1.9.3-p448
       ruby-2.0.0-p0
       ruby-2.0.0-p195
       ruby-2.0.0-p247

Ruh-roh!

Now, I know 1.8.7 is ancient news, but I didn't think they'd drop support for it so entirely.

I went wandering about looking for a way to specify an older repository - perhaps the 10.04 repo would still have 1.8.7 in a useable format...

Turns out I'd just made a simple mistake, easily rectified.

The important clue was in the last line of the result for rvm install:

You requested building with 'gcc-4.4' but it is not in your path.

I'd copied a whole bunch of things across to the new 'puter, including my .zshrc file - which is what was specifying the gcc version (can't remember why). And on the new 'puter I had gcc version 4.6 but my .zshrc (copied from my previous computer) was pointing at this older version.

Because of this small mistake, rvm thought I didn't have a c-compiler. Which means that rvm wasn't able to install any rubies from source - only pre-compiled rubies - which means it was restricted to only those already pre-compiled for my platform (ie 64-bit ubuntu 12.04).

oops.

When I fixed the gcc line in my .zshrc - rvm was able to figure out how to install+compile source-code rubies - including v1.8.7

Sunday, 30 June 2013

How to shop at Ikea...

Step 1. recognise that you have a problem.
Decide that ikea has the perfect solution.

Step 2. Find a time where you know you have four hours spare (just in case), but convince yourself that you're only likely to be there for an hour or so.

Step 3. struggle for two hours through a labyrinth of perfect mini-houses and dawdling shoppers trying to find the thing you know is there somewhere... you've *seen* it the last time you were here...

Step 4. Along the way discover solutions for five other problems you'd forgotten you had. Write down prices and numbers for ALL the Things!!!

Step 5. You reach the end. Stop for meatballs.

Step 6. Spend a few minutes adding it all up on paper to discover that you'd be spending the next five pay-checks paying back the credit card debt to cover it. Cut it down to only two or three things you most need.

Step 7. Refreshed and ready. Head downstairs to pick up your things... and suddenly re-discover the kitchen section... and remember that you needed some wine glasses, and you loved that metal bowl and could do with another one... and oh! memory-foam pillows, you need a spare! etc etc...

Step 8. Get to the warehouse section and discover there's no flat trolleys, there's a queue of ten people waiting already and they're somehow closing in fifteen minutes. wait... and wait... and wait... plan the order-of-attack for hitting the aisles at a run.

Step 9. Eventually get to the first aisle... and discover you wrote down the wrong number for this item, and without it, almost all the others are useless.
Give up and decide you'll just get the original item *only*. try not to feel bad about the additional two hours of lost time spent choosing these items.

Step 10. Get to the aisle and discover that it comes in a set of *three* huge boxes. Heave them onto the trolley. Think to yourself... holy shit, I don't remember the boxes being that long... how the hell are they going to fit in the hatchback?

Step 11. navigate the trolley towards the checkout... as you try to turn it, remember that these trolleys work on hovercraft-physics, and have about the same leeway... try desperately to stop five times your own bodyweight of flat-packed MDF as it begins to slew into a pair of inattentive shoppers that are drifting about in front of you without looking... discover that the best course of action is to yell maniacally "I can't stop this thing!!!" while they stare at you in horror and clutch small children to their shaking breast.

Step 12. When you're finally waiting in the queue, remember that they do deliveries! You won't have to fit the boxes in the car after all! ... Get to the deliveries desk and re-discover that Ikea assumes that *everybody* has a house-wife willing to be there from 12-noon to 8pm for when they decide to show up... and they will *only* do next day delivery. Decide you want to keep your job, and go fetch your car.

Step 13. break a nail off and bleed profusely getting the first long box in the car... realise that even with the back seats down and the front seat far forward, it's still sticking out by 5cm... of course you knew this was going to happen.

Step 14. use the remaining shreds of your undergrad maths to figure out a topologically viable solution that will allow you to slam the hatchback closed before the carpark closes for the night... When you do, realise you have zero side-vision on your left, it's pouring with rain and pitch dark outside... hope to god that nobody does anything stupid on that side of you tonight. Decide to see the silver lining - if you die, at least you won't see it coming.

Step 15. get to the exit gates and discover that you were in the carpark for your free three hours... and 15 minutes - about the same time you spent struggling to get the boxes into the car... and for which you now owe $8.
Don't forget to drop your credit card on the ground after the *first* time the machine rejects it... apologise to the three cars behind you in time for it to reject you a second time.

Step 16. discover you have to turn left when leaving the carpark. You know this when twice your bodyweight in MDF suddenly slides off the passenger seat onto your left shoulder. Resolve to drive like a granny until you get home...

Step 17. as you continue to drive... try to repress the sinking feeling that accompanies your realisation that you don't have a trolley at the other end...

Wednesday, 5 June 2013

Gotcha: undefined method `render' for SomeTemplate

I recently had to scratch my head over a strange exception message I'd never seen before:

undefined method `render' for #<SomeTemplate:0xb17da594>

The problem was, it came with *no* application trace at all... just the usual Rails stack-trace.

I had to guess at where the problem came from by grepping for SomeTemplate in the controller-action that had exploded, and came across the following line of code:

  @template = SomeTemplate.new(params[:some_template])

Now SomeTemplate is a model of ours, and prior to this error occurring that line of code had been:

  @temp = SomeTemplate.new(params[:some_template])

I have a strong aversion to calling any variable "temp", because my reaction to seeing a variable called temp is to say "a temporary what?" not "oh, that's an instance of a template", and if I'm getting the wrong idea when I look at a variable name - that's an indication it should be changed.

So I renamed it...

Unfortunately, it turns out that @template is a magic variable in Rails that refers to the template to be rendered in a given controller action.

So Just Don't Do That.

The code has now been rewritten to the following, and works just fine:

  @some_template = SomeTemplate.new(params[:some_template])

Thursday, 30 May 2013

Your Open Source Report Card

Have a look at your own Open Source Report Card. It dives into your github commits and generates a description of your coding propensities - skills and habits.

You might even find out something you never knew about yourself - apparently I'm a Tuesday tinkerer!

Here's mine for a comparison taryneast

Tuesday, 21 May 2013

Backporting "in_array" to older versions of should'a "ensure_inclusion_of"

Here's another shoulda backport I added recently. If you're still stuck using a legacy Rails system, this backport will let you use "in_array" in the "ensures_inclusion_of" Matcher.

Save it into something like: config/initializers/shoulda_monkeypatches.rb, then use it like this:

   should ensure_inclusion_of(:widget_status).in_array(Widget::VALID_STATUSES).allow_blank.with_message(:is_invalid).use_integer_test_value
  # backport the "in_array" method for the ensure_inclusion_of matcher
  # While we're at it, add allow_blank and allow_nil too
  module Shoulda # :nodoc:
    module ActiveRecord # :nodoc:
      module Matchers
        class EnsureInclusionOfMatcher
          ARBITRARY_OUTSIDE_STRING = 'shouldamatchersteststring'
          ARBITRARY_OUTSIDE_INT = -999999999

          # to initialize the options
          def initialize(attribute)
            super(attribute)
            @options = {}
          end

          # add the method we want to allow us to pass in arrays instead of
          # just ranges
          def in_array(array)
            @array = array
            self
          end          

          # might as well also add the allow_blank and allow_nil methods too
          def allow_blank(allow_blank = true)
            @options[:allow_blank] = allow_blank
            self
          end

          def allow_nil(allow_nil = true)
            @options[:allow_nil] = allow_nil
            self
          end

          # This is a method of my own addition to point out that the
          # test-value must be an Int, not a String... because a string can
          # evaluate to 0 which is a valid Int... which will make the test
          # pass where it shouldn't :P
          def use_integer_test_value(only_integer = true)
            @options[:use_integer_test_value] = only_integer
            self
          end

          # override description so it doesn't just try to inspect the range
          def description
            "ensure inclusion of #{@attribute} in #{inspect_message}"
          end

          # override the matches method to allow arrays as well as ranges
          def matches?(subject)
            super(subject)

            if @range
              @low_message ||= :inclusion
              @high_message ||= :inclusion

              disallows_lower_value &&
                allows_minimum_value &&
                disallows_higher_value &&
                allows_maximum_value
            elsif @array
              if allows_all_values_in_array? && allows_blank_value? && allows_nil_value? && disallows_value_outside_of_array?
                true
              else
                @failure_message_for_should = "#{@array} doesn't match array in validation"
                false
              end
            end
          end

 
        private

          # provide the message-inspect method to use either array or range
          def inspect_message
            @range.nil? ? @array.inspect : @range.inspect
          end          

          # array helper methods
          def allows_all_values_in_array?
            @array.all? do |value|
              allows_value_of(value, @low_message)
            end
          end

          def disallows_value_outside_of_array?
            disallows_value_of(value_outside_of_array)
          end

          def value_outside_of_array
            test_val = @options[:use_integer_test_value] ? ARBITRARY_OUTSIDE_INT : ARBITRARY_OUTSIDE_STRING
            if @array.include?(test_val)
              raise CouldNotDetermineValueOutsideOfArray
            else
              test_val
            end
          end

          # blank and nil helper methods

          def allows_blank_value?
            if @options.key?(:allow_blank)
              blank_values = ['', ' ', "\n", "\r", "\t", "\f"]
              @options[:allow_blank] == blank_values.all? { |value| allows_value_of(value) }
            else
              true
            end
          end

          def allows_nil_value?
            if  @options.key?(:allow_nil)
              @options[:allow_nil] == allows_value_of(nil)
            else
              true
            end
          end         




        end

      end
    end
  end

Tuesday, 30 April 2013

Enforced computer-free time

Gah - I've been computer-free for the past week, and not by choice.

My ageing macbook suddenly started to switch off... at random. This was ok for a while... but when it took four times for it to even get through the boot process - I had to take it into the Apple shop. meanwhile I finally set about getting a new desktop, and work gave me a new macbook to try and use.

I couldn't get the monitor to work on the desktop, and the macbook is too new to run the current ubuntu LTS (though I somehow managed to get 9.10 to install... but it won't find the ethernet port)...

I've finally got the desktop working (I was using the wrong video connection) but I still can't get mail to work properly (the joys of mail on a linux machine...), and my macbook is back from the shop... but the ethernet isn't working.

soooo.... still no email and it's been a week. But at least I have google now.

You realise just how dependant on something you've become when you suddenly don't have it anymore.

You also find just how stuck you can be. How do you find the location of a good internet shop if you don't have access to google to look one up? There used to be a directory-services phone number, but I have no idea what that is anymore, and of course I don't have a copy of the yellow pages anymore (who bothers with those when you have google)?

Wednesday, 24 April 2013

Ubuntu without the Unity!

For some time now my ageing (and now quite flaky) Macbook Pro has been running Lucid Lynx (an older version of Ubuntu). I've been biding my time and avoiding upgrading since, well, April 2010, I guess.

For most of the time it was because upgrading your only machine that you rely on for 100% of your income, to a potentially unstable, non long-term release version is generally a bad idea; but then, when I went to a new employer, I tried a new install of the new long term release... and slammed headlong into the weirdness that is the Unity Interface.

To sum up my experience: when I buy a desktop, I want it to *be* a desktop... not a iPad.

Now - maybe I'm just being backwards and should embrace the new unified interface which I'm told is meant to be amazing... if a little bloated.. and sometimes corrupts your file system if something goes wrong... but this is still my only machine (for now) and I need to be sure it's ok. I don't want to upgrade to Unity.

Of course, there is now a new long-term-release version, and sadly, the old one is now no longer supported, so I'm feeling a bit like a sprite in an old platform game, being relentlessly pushed towards the future by the scrolling screen...

Thankfully, I've malingered just long enough for the Ubuntu Gnome project to have been officially blessed by . it's not an LTR version yet, but it will be.

Until then - it's also possible to upgrade to the LTR but keep gnome. I've been putting it off because I'm ultra-busy and kept finding other, much more important things to do than figuring out how to do it myself... but I've just found a neat article on how to change your ubuntu interface to gnome.

Just what the doctor ordered

Friday, 12 April 2013

Huge medieval camping event - come and join in!

war at Rowany festival

The reason it's been so quiet around here this month is that I've been crazy busy in my main hobby due to our major event for the year (run by our local group).

Rowany Festival is the largest Medieval re-enactment event in the Southern Hemisphere. I've heard it described as "kind of like Burning Man but with a medieval theme" - we prepare all year for this!

This year 800 of us all got together at Peats Ridge and camped medieval-style, fought wars, sang, danced, drank a *lot* of booze (some of it made by me) and generally had a great time...

Needless to say not a lot of Ruby got written... but that'll pick up again now I've got most of my washing done and camp kit packed away again.

If you'd like to join me on this stuff - I'm the president the NSW branch of the SCA, known as Rowany. The Australian kingdom is called Lochac (and also covers NZ too).

The whole Society is huge: 100,000 worldwide, and we all run regular events (camping roughly once a quarter, and feasts/tourneys once a month and just general hanging-out and learning fun stuff every week) and it's a great deal of fun.

Come along to our casual fighter-practice which is held on Tuesday nights at Petersham Town Hall on Crystal St (near to Petersham Station). We regularly get 30-50 people every week and they're running beginners fighting classes right now*. We also have regular singing, Calligraphy fibre-craft and costuming days every month.


* its $5 a night for non-members, or you can join for a year for $30 - but you have to do your membership online here (we're not allowed to take payment directly for that)

Picture Credit: Enough Wealth: Rowany Festival

Tuesday, 5 March 2013

Link: Why Yammer believes the traditional engineering organizational structure is dead

This is a great article describing the way that Yammer has set up its organisational structure to be nimble and effective. Why Yammer believes the traditional engineering organizational structure is dead

Highlights for me:

Yammer’s biggest rule of thumb is “2 to 10 people, 2 to 10 weeks,” ... If you employ the “2 to 10″ rule, it’ll also force you to release often, test your assumptions, and not over-invest in mistakes.

and

While everybody knows how expensive context switching is, it’s staggering that nobody builds that into their organization as a constraint. With total focus, you build one thing, ship it, and then are able to move onto something else.

Thursday, 14 February 2013

Quick and dirty facebook feed parsing

So, there's this big discussion going on for my hobby group at the moment, and the main discussion has been going on in facebook - mainly because that's where I was first asked to set up a discussion and it took all of five minutes to get the page up and running.

However - now that discussions are progressing, there are a number of people *outside* the facebookiverse who have raised quite reasonable objections to the discussion happening there. not everyone is on facebook, not everyone *wants* to be on facebook, and to be honest, a facebook group kinda sucks for searching and archiving really important discussions.

thus it has been requested that I copy all the posts and comments to Someplace Else, to make them available for more general consumption.

At first I balked at this request - 24 posts and 250 comments to be individually copied/pasted??? Who has that kind of time?

Of course when I actually sat down to think about the problem seriously, it took far less time than I though to solve it. So here's what I did, including the quick-and-dirty ruby script that will massage the facebook feed into something that resembles readable format. It aint pretty - but it'll pass for government work.

Step 1: get the feed from the API

I'll assume you are actually a member of the group that you're after. You will need to be.

You need to go to your group and get the group's ID from the URL.

The facebook API page is here: Facebook Graph API explorer

First you need to create an access token to get the data out of facebook. This is essentially the same as doing one of those "allow application to access my data" things that you click on when you add a new app. In this stage, you need to allow the Graph-API application to access *your* group-data, to prove that you have access to he feed of the group - and to allow it to fetch out all the posts for you.

  1. click the "Get access token" button
  2. Select the "user_groups" checkbox
  3. click the new "get access token" button
  4. follow any prompts (if this is the first time using this API, you'll get the "allow access for this application" process - but it may not happen for subsequent attempts

You should now have a long encoded token in the box at the top of the page.

Next up we need to tell it what feed to use. There's a drop-down labelled "GET" which you should leave as-is. In the text-box next to that, type in the ID of the group in a URL-format like this: /1234567890?fields=feed and then click "Submit". The "fields=feed" tells the API to actually go and fetch the feed of posts and comments.

At this stage, you should be able to see a huge hash full of posts and comments in the box to the right hand side of the screen. Copy and paste that into a file.

Step 2: massage it into shape

Now you've got your feed data, you just need to play with it and spit it out into a nicer format. In our case, I decided to go for just a rough html format that showed what the posts were, what comments were attached, and who said what. My script is posted below - which can serve as a starting point for whatever you'd like to see done.

This script accepts the input filename and an optional output filename (or it just jams '.html' on the end of the input filename). It'll generate a really rough-and-ready html file that contains the posts and comments (with names and datetimes) plus some of the links (if present).

Enjoy...


#!/usr/bin/env ruby

DATE_FORMAT = "%H:%M:%S %d-%m-%Y"

class Object
  def blank?
    self.nil? || (self.respond_to?(:empty?) && self.empty?)
  end
  def present?
    !self.blank?
  end
end

new_file_name = nil

# if they've passed in the filename, use it
if ARGV && ARGV.length >= 1
  file_name = ARGV[0]
  if ARGV.length > 2
    new_file_name = ARGV[1]
  end
end
if file_name.blank?
  p "usage: facebookfeed <file_name> [<outfile_name>]"
  exit(1)
end
p "got file_name of: #{file_name}"

unless File.exists?(file_name)
  p "file: #{file_name} does not exist"
  exit(1)
end

# munge up an html filename for the output file
new_file_name ||= file_name.split('.').first + '.html'


if File.exists?(new_file_name)
  p "output file: #{new_file_name} already exists, please supply another"
  p "usage: facebookfeed <file_name> [<outfile_name>]"
  exit(1)
end

# parse json in file into ruby - preferably a hash
require 'rubygems'
require 'json'
require 'date'
facebook_hash = JSON.parse(IO.read(file_name))

feed_data = facebook_hash["feed"]["data"]



if feed_data.present?
  File.open(new_file_name,'w') do |outfile|
    puts "parsing #{feed_data.count} posts"
    sum = 0
    feed_data.each {|post| sum += post["comments"]["count"].to_i }
    puts "with: #{sum} total comments"

    feed_name = feed_data.first["to"]["data"]["name"]

    # html headers go here
    outfile.puts "<html>"
    outfile.puts "<head><title>#{feed_name}</title></head>"
    outfile.puts "<body>"
    outfile.puts "<h1>#{feed_name}</h1>"

    feed_data.each do |post|
      outfile.puts "<p>by <b>#{post["from"]["name"]}</b> at: <b>#{DateTime.parse(post["created_time"]).strftime(DATE_FORMAT)}</b></p>"

      if post["picture"].present?
        outfile.puts "<div style=\"float:left;\"><img src=\"#{post["picture"]}\" /></div>"
      end
      name_str = post["name"]
      name_str = "<a href=\"#{post["link"]}\">#{name_str}</a>" if post["link"].present?
      outfile.puts "<h2>#{name_str}</h2>"

      message = post["message"]
      message.each do |para|
        outfile.puts "<p style=\"clear:both;\">#{para}</p>"
      end

      comments = post["comments"]

      if comments.present? && comments["count"].present? && comments["count"].to_i > 0
        outfile.puts "<h3>Comments</h3>"
        outfile.puts "<dl>"

        comments["data"].each do |comment|
          outfile.puts "<dt>by <b>#{comment["from"]["name"]}</b> at: <b>#{DateTime.parse(comment["created_time"]).strftime(DATE_FORMAT)}</b></dt>"
          outfile.puts "<dd>#{comment["message"]}</dd>"
        end
        outfile.puts "</dl>"
      end #any comments present
      outfile.puts "<hr />"
    end # each post

    # html footers go here
    outfile.puts "</body>"
    outfile.puts "</html>"
  end # with open outfile
end #feed data present

Friday, 8 February 2013

Link: What rails security means for your startup

If you hadn't already heard, Rails has a security vulnerability that affects all versions of Rails. This one is about XML-parsing of YAML strings.

This was followed by a second vulnerability in the JSON parser - again of YAML-parsed code.

So what does this all mean for all of us running Rails-based systems? Is this just a flash-in-the-pan issue that will fade away the moment it's out of the public eye? or is it a herald of the coming apocalypse?

A really cogent overview of what the rails security issue means for your startup has been written by Patrick, and I strongly recommend you read it, and pass it on.

Amongst a number of useful overviews, it covers such things as "yeah, but we're not a high-profile site, nobody's going to attack us right?" and concludes that the worst may not yet be past, and that:

You Should Be At Defcon 2 For Most Of February

Saturday, 2 February 2013

Link: Help Vampires: A Spotter’s Guide

Here's a great post on the ubiquitous "Help Vampire" who drains the life out of helpful communities...

Help Vampires: A Spotter’s Guide gives tips on how to spot, avoid and reform them for the future benefit of humanity...

Sunday, 27 January 2013

XML-YAML-parsing security fix for older versions of rails

Earlier I mentioned the Serious Rails vulnerability that affects all versions of Rails for the last six years.

A fix has been put into the latest versions of Rails 2 and 3. but it requires you to upgrade to the latest version.

If you have an older version of rails and can't upgrade for various reasons (eg we are still stuck on v 2.3.2 due to some legacy code), there's a better fix for the *link* xml parsing error than the workarounds on offer (which tend to switch off your ability to parse XML).

The fix that we've done requires that you use bundler, though you could equally-well freeze rails into vendor/gems and make the same patch there. We chose the bundler/github approach because it reduces the size of our repository.

Step 1: fork a copy of rails for yourself

  1. fork rails
  2. git clone it into a local directory.
  3. checkout the *tag* that corresponds with the version you are on (eg for us: v2.3.2.1) - you can see what tags there are by running: "git tag -l"
  4. Don't worry about the big scary message it gives you about a detached HEAD - that just means you've got a specific commit checked out instead of a branch.
  5. create a branch for yourself eg for us: git branch v2.3.2_xmlfixes
  6. checkout that branch eg git checkout v2.3.2_xmlfixes
  7. push that to your repo on github with eg: git push -u origin v2.3.2_xmlfixes

Now you have a forked copy of the rails repo with a branch at the rails-version you are using that you can refer to in your Gemfile.

Step 2: actually apply the patch...

cherry-pick this commit (which if you look at github is is the one from v 2.3.15 that fixes this very error). Using:

git cherry-pick 70adb9613e4a40c5645c99da37

Note: You are likely to get conflicts with the CHANGELOG - you can keep them or just throw them away as you wish (it's just the changelog which describes the latest changes).

commit and push to your repository.

Now you have a patched version of rails in your git repository.

Step 3: update your Gemfile

Your Gemfile is likely to have a line that includes rails such as:

gem 'rails', '2.3.2'

You need to update that line to point at *your* git repository and your new branch.

The following *should* Just Work:

gem 'rails', '2.3.2', :branch => "v2.3.2_xmlfixes", 
:git =>l 'git://github.com/<your_git_repo>/rails.git'

To find the git url, you can go to your forked copy of git, look near the top of the page where it has a text-box with a git-link. Make sure you click on the "Git Read-only" button, and copy what's in the box on the right.

The branch to use is whatever you named your branch in step 5 above.

You should now be able to run bundle install to regenerate your copy of rails - and it will pull the details from your forked-and-patched copy

Troubleshooting

Unfortunately, when I used the above, it bundled correctly, but any attempt to spin up the server just caused the following error:

./script/../config/boot.rb:61:in `require': no such file to load -- initializer (LoadError)
 from ./script/../config/boot.rb:61:in `load_initializer'
 from ./script/../config/boot.rb:117:in `run'
 from ./script/../config/boot.rb:17:in `boot!'
 from ./script/../config/boot.rb:130
 from script/server:2:in `require'
 from script/server:2

Luckily the answer is in the StackOverflow question: how to use a branch in a fork of rails in a project with bundler.

First, you need to add .gemspec files into your patched copy of rails. If you're forking 2.3.10, you can copy the gemspec files from the commit Adding .gemspec files for all gems in the 2-3-stable version of rails created by the author of the above stackoverflow issue.

Otherwise you'll need ones correct for your own version. The commit above talks about generating them from the associated Rakefiles. I created them by copying the gemspec files listed in the commit above, and then just copying over the spec = Gem::Specification block with the equivalent block that is in the Rakefiles.

eg for actionpack.gemspec, I copied the actionpack.gemspec from the commit into the rails/actionpack directory in my forked copy of rails. Then I opened up rails/actionpack/Rakefile and copied the whole block of code that begins with spec = Gem::Specification into the actionpack.gemspec file, deleting the previous block from that file first.

You will know if you got the gem-dependencies wrong if you get an error like the following:

Bundler could not find compatible versions for gem "activesupport":
  In Gemfile:
    actionpack (>= 0) ruby depends on
      activesupport (= 2.3.10) ruby

    activesupport (2.3.2)

Now you have generated the gemspecs, add them to your forked copy of Rails, commit them and push the commit to your github repo.

Then you can put the following in your Gemfile:

:git => 'git://github.com/<your_git_repo>/rails.git', :branch => "v2.3.2_xmlfixes" do
  # Note: load-order is essential for dependencies
  gem 'activesupport',  :branch => "v2.3.2_xmlfixes" # this must go first
  gem 'actionpack',     :branch => "v2.3.2_xmlfixes" # this must go second
  gem 'actionmailer',   :branch => "v2.3.2_xmlfixes"
  gem 'activerecord',   :branch => "v2.3.2_xmlfixes"
  gem 'activeresource', :branch => "v2.3.2_xmlfixes"
  gem 'rails',          :branch => "v2.3.2_xmlfixes" # this must go last
end 

Note: make sure the gems are in the order above, with rails last - otherwise you'll get something like:

Could not find gem 'activesupport (= 2.3.10) ruby', 
   which is required by gem 'activerecord (>= 0) ruby', in any of the sources.

Also note: you *must* explicitly set the branch on the git-repo line and *also8 on all the gem-lines (and they must match) otherwise bundle install will work fine, but if you try anything else you'll get the infuriating error:

git://github.com/<your_git_repo>/rails.git (at v2.3.2_xmlfixes) is not checked out. Please run `bundle install`

Finally

you should now be able to run bundle update and bundle install and it should now work.

This has been tricky to explain, and the steps are complex - if something's not clear, let me know and I'll try and make it more plain.

Monday, 21 January 2013

Link: DHH - testing like the TSA

Learning how to test is an important skill, learning what *not* to test is also an important skill. DHH shares his thoughts on this subject, with a brief article: Testing like the TSA which cuts through the "security theatre" aspect that can sometimes begin to surround our testing efforts.

There's also a long discussion on Y-combinator about the article here Hacker News: Testing like the TSA

Tuesday, 15 January 2013

Link: Why 2012 was the best year ever

So many people are on the doom-and-gloom bus - so much so that it blinds them to the spectacular, amazing things happening in the world today. New things are being created and built, and medicine is practically screaming along.

Not that this stops the doom-sayers who claim, darkly that it all comes at a heavy price, that the advances of the first world are killing the rest of the world, and that poverty and death are on the rise...

Well, pooh to that. Here's an article that explains that actually, the world is improving at a rapid pace, including all of the usual favourite doom-and-gloom topics: Why 2012 was the best year ever

Read that before you try and tell me we "shouldn't bring children into this world" or that the world isn't as good as it was back when...

Wednesday, 9 January 2013

Serious rails vulnerability - read this!

A serious vulnerability in *all* versions of rails (for the last six years) has been spotted.

In brief: complex xml-style params go through an XML-parser that will interpret based on types. "yaml" is a valid type, and that loads the YAML-parser... which instantiates any embedded classes that can include arbitrary code - leading to all kinds of injection-attack possibilities.

A general discussion of the problem, including patched versions and workarounds for old versions is available here: Multiple vulnerabilities in parameter parsing in Action Pack

A more in-depth look at what the problem entails is available here: Analysis of Rails XML Parameter Parsing Vulnerability

Thursday, 6 December 2012

Link: Everything you need to know about the National Broadband Network

Hi all, this one is aimed at other Australians. Since it was first announced in 2009, there's been a lot of rumbling about the National Broadband Network plan - what it actually is, whether it's worth it, what it actually means for us or for the Australian budget etc etc

This link provides an article that fully explains what it's all about and is well worth a read.

The NBN: everything you need to know

TL;DR: it's a plan to replace the antiquated Telstra copper-network with high speed fibre (preferably to-the-home) so that we can keep up with the massive influx of bandwidth we're all using these days just like all the other high-tech countries did ages ago... and yes, it's worth it.

Friday, 30 November 2012

Link: Why engineers are grumpy

There have been many great articles on how to deal with IT-folks. This is another of them: The care and feeding of software engineers (or, why engineers are grumpy)

It explains: what makes engineers tick, what makes them grumpy and why, and also solutions to make it all Just Work. It covers both the strengths and weaknesses of engineers, and how to build on the former, while avoiding the latter.

I'll leave you with a few quotes:

In almost every other industry where things are built, it is expected that all requirements and details are agreed upon and finalized before building commences. Except in software. In software there’s “not enough time” to gather all the requirements ahead of time. The importance of moving quickly is hammered into us from day one. And so engineers learn to fill in the gaps left by product managers just to keep the project going. Product managers, of course, also have the reputation for changing their minds frequently, which means engineers assumptions are often invalidated partway through the process. Is it any wonder that software engineers tend to burn out quickly and change jobs frequently?
True priorities aren’t transient, they are static. The frequency with which people above us change their minds is incredibly frustrating for software engineers. We frequently stand ready to march into battle and just want a direction to march in. But if you tell us one day that we’re building a house and the next day that we’re building a car, you should expect some dissension in the ranks.
There are few phrases that anger software engineers more than, “I used to code.” ... If I were to ask LeBron James how much time he needs to prepare for a game, I’m sure he’d be amused if I disagreed because I played basketball in high school. Software engineers get the equivalent all the time.
We software engineers are an interesting bunch. There’s a definite personality that comes along with us, and we really do want to make the best thing possible. If you stop treating us like short-order cooks and start treating us like part of the creative process, you are likely to get much farther, faster than you would otherwise. The teams on which I’ve worked have all had varying degrees of friction caused by not understanding the engineers’ mindset and what drives them. It’s my sincere hope that this article will lead to better communication between engineers and those that they work with. It’s really not that hard. We’re all just people who want to feel like a part of the solution rather than a worker bee.

Saturday, 24 November 2012

Deleting un-named foreign keys in a migration

So, we use foreign-key constraints in our db. It's pretty annoying to get Rails to work nicely with that, but we have some basic helper methods (which I didn't write, so I cant share).

However I recently had some trouble dropping an old table. I kept getting these errors:

Mysql::Error: Error on rename of './mydbname/#sql-1ca8_f7842' to 
   './mydbname/my_table_name' (errno: 150): DROP INDEX `my_table_name_idx3` 
   ON my_table_name

I discovered that this was because it had foreign-key constraints. The awful error message is itself listed as a bug on mysql... but the real problem is that it doesn't want to drop an index I've asked it - because there's a foreign-key constraint on the column referenced by that index*.

Fair enough.

Unfortunately, the "remove_foreign_key" code we have assumes the foreign-key has been named in a certain way (table_name_column_name) but in this case it wasn't. So Trying a drop index on that caused it to give an equally unhelpful message along the same lines...

This foreign key has been hanging around since the dawn-o-time, and it has one of those automagically-generated constraint-names built by the db itself... something like: my_table_name_ibfk_16.

Now that'd be fine to drop if we just had one client. with one database... you can easily put the following into a migration:

   execute "ALTER TABLE `my_table_name` DROP FOREIGN KEY `my_table_name_ibfk_16`" 

Unfortunately for us, we have 150 clients - each with their own db... and it looks like that constraint-name differs depending on which order the foreign-keys got created. ie sometimes it's my_table_name_ibfk_16 and sometimes it's my_table_name_ibfk_3 - and if you drop it by number - you could be killing the WRONG foreign-key constraint... which would just be embarrassing.

The way out of this quandary is to query the information_schema table to find the foreign-key's actual constraint-name. and here it is for your amusement. (note: put this into initializers eg by saving it as config/initializers/migrations.rb

class ActiveRecord::Migration
  # grab the db-name out of the connection and persist it
  # it's not going to change over the course of a single migration
  def self.fetch_database_name
    @@database_name ||= connection.database_name
  end

  # Use this if the foreign-key was created without an explicit name - 
  # and has one of the automatically-generated constraint-names.
  #
  # This method queries the information-schema table to fetch out the key
  # name before continuing to drop the foreign-key
  #
  # Use this in your migrations with:
  #    remove_legacy_foreign_key :table_name, :field_name
  # eg:
  #    remove_legacy_foreign_key :widgets, :wodget_id
  def self.remove_legacy_foreign_key(table, column_name)
    # first pull the foreign-key name from the information schema
    result = execute "select constraint_name from information_schema.key_column_usage as ke where ke.table_schema = '#{fetch_database_name}' and ke.table_name = '#{table}' and ke.column_name = '#{column_name}';"
    name = result.fetch_hash['constraint_name']
    raise "Got no foreign key by that name" unless name.present?
    execute "ALTER TABLE `#{table}` DROP FOREIGN KEY `#{name}`"
  end
end

[*] Note: mysql also gives a similar error if you're dropping a foreign-key constraint that doesn't exist at all by the name you give it:

ERROR 1025 (HY000): Error on rename of './mydbname/my_table_name' to 
   './mydbname/#sql2-1ca8-f6cc5' (errno: 152)

Saturday, 17 November 2012

Kiva is addictive

No IT angle today...

I have a mixed approach to giving to charity. I have a number of regular direct debits for various causes, and I also give sporadically in lump sums when inspiration strikes me.

My latest of these is Kiva (here's a Kiva invite) - which is a site that does micro-loans to people in developing countries.

Kiva has been on my radar for a while now, but I'd been putting it off because I had a few misconceptions about the whole process and I finally got down and actually did some reading on what it's all about.

I was mainly concerned by the fact that in most cases, the loans have already been given out, and you are paying for something that is already a fait accompli - which I thought was weird, and that it meant that you weren't really lending the money to the people you had chosen.

Turns out to make a bit more sense. These people need loans immediately, so the partner in that country does so, and then posts the loan up to Kiva. When you choose to "fund" that loan, your money then underwrites it. You are taking on the risk for the loan.

Now I've had it explained, it makes sense to me, so I've been having fun donating... it's a bit more addictive than I expected. I've already made five loans in as many countries, three of which have now been fully funded - one of which I was the final person that funded it (and that feels pretty good). We'll see how they go.

Thursday, 8 November 2012

Link: Unit tests don't find bugs

A quick article called unit tests don't find bugs points out what unit tests are really for, and advises us not to forget that unit tests cannot be used as a substitute for QA-style testing.

Friday, 2 November 2012

ruby gotcha: beware trailing commas

I had something like the following (though with more values):

 h = OrderedHash.new()
 h[:a] = {:a => 1}
 h[:b] = {:b => 2}, # note the trailing comma - oops
 h[:c] = {:c => 3}

and started getting errors telling me that h[:b] was an array, when I was expecting it to be a hash...

Here's what's actually happening (via irb):

>> a = {:a => 1}
=> {:a=>1}
>> b = {:b => 2},
?> c = {:c => 3}         # still part of the previous statement
=> [{:a=>1}, {:c=>3}] # so we end up with an array

Note to self: beware trailing commas

Saturday, 27 October 2012

[SOLVED] undefined method `name' for "Ascii85":String

So, we're still using Rails 2.3.2 for our client... but I'm *trying* to upgrade it piece by piece. In doing so, I recently had to upgrade rubygems, so that it would work with a recent version of a gem we desperately needed.

Unfortunately it led to the undefined method `name' for "Ascii85":String bug that I wrote about when I last tried to upgrade rubygems

Back when it broke rubygems the first time, the only solution seemed to be to downgrade rubygems and hope for a future time when I could upgrade everything and get it working again.

But that wasn't an option this time... and so I had to hack up a solution.

The problem is described below in solution 2, but it's basically a problem with rails - which isn't using the newer rubygems gem-comparing "==" function properly any more.

Solution 1: Gem bundler

One solution that definitely works is to upgrade to using gem bundler (or the Rails2.3 version of bundler).

This definitely works because bundler doesn't have the same bug in it that Rails 2 has - it uses gem-comparison the new way.

But some of our clients aren't on the bundled release yet, and I need to quickly fix bugs and push to those clients... so I needed a solution that would let me still load the bundler-free version without having to downgrade rubygems to do it.

Solution 2: Fix rails

This solution requires a (very small) hack on Rails... but I figured that was ok as it was just to get my own system working so I can fix things without having to go through the pain of installing rvm (which I don't have time for right now).

So far the fix seems to be working, so I'll share (with the caveat that it's not well tested yet so YMMV).

The problem is really a Rails bug... not rubygems. So that's where you can safely hack (for now). From the stacktrace of the bug, find the copy of "rails/gem_dependency.rb" that is causing the issue:

/usr/lib/ruby/gems/1.8/gems/rails-2.3.2/lib/rails/gem_dependency.rb:239:in `==': 
undefined method `name' for "Ascii85":String (NoMethodError)
 from /usr/local/lib/site_ruby/1.8/rubygems/dependency.rb:218:in `==='

In my case, I opened /usr/lib/ruby/gems/1.8/gems/rails-2.3.2/lib/rails/gem_dependency.rb in a text editor (with sudo permissions). It'll have something like the following:

    def ==(other)
      self.name == other.name && self.requirement == other.requirement
    end

The actual problem occurs because Rails is sometimes passing the name already as a string to this function, instead of an actual spec. So to fix it, we just check for that with the following code:

    def ==(other)
      # The following line has been inserted to get around the bug:
      # "undefined method `name' for "Ascii85":String (NoMethodError)"
      return self.name == other if other.is_a?(String) # bugfix
      self.name == other.name && self.requirement == other.requirement
    end

It shouldn't alter existing functionality, it'll just get past the broken code that is in rails until you can upgrade rails, or use bundler.

If you (horror) actually need to install this fix on a live system; I'd recommend freezing rails to your gems directory before applying the fix. But in reality, I'd actually recommend just finding a way to upgrade to using bundler. It's a neater solution that won't require ongoing maintenance.

Sunday, 21 October 2012

Link: Primer on sexism in the tech-industry

"The topic of sexism and its role in the technology industry has seen a huge resurgence over the past 12 to18 months. Yet despite being discussed and examined with increasing frequency, a lot of the subject remains unclear and under-explained, making it difficult for those who care deeply about our industry to partake in these discussions. This is, in part, because the problems are incredibly complex, nuanced and difficult to explain, making it impossible for any one article to address them sufficiently (lest that article becomes a book). Nevertheless, today we're going to try and see how much of the basics we can clear up."

Faruk AteÅŸ has written a most-excellent primer on sexism in the tech industry

You should read this (especially if you are male) before even considering posting an article or comment about women in the tech industry.

Monday, 15 October 2012

Making views/triggers/functions work in mysql for rails

We use mysql with Rails. We also use foreign-keys, views, triggers and stored procedures.

Rails's mysql gem still doesn't know how to handle any of the above yet... which is kind of inconvenient if you want to test your application.

The problem arises because even with a SQL schema dump - it only dumps the tables and foreign keys. No views, no triggers, no stored procedures. If you have code that relies on these... your application starts getting MySql errors.

Luckily there seems to be a solution with the db_structure_ext gem, which I've been using happily now for a couple of weeks.

I found the README isn't at all clear as to how to get it set up, so here's some basic instructions on how I made it work with MySQL on Rails 2.3.X

1) Install it as per the README:

gem install db_structure_ext and/or add gem 'db_structure_ext' to Gemfile and then bundle install

2) require it in your Rakefile

# extended db-structure-dump (also does triggers, routines etc)
require 'db_structure_ext/tasks'

3) Monkey-patch ActiveRecord

Create a file call config/initializers/mysql_adapter.rb (or similar) and add the following code:


module ActiveRecord
  module ConnectionAdapters
    class MysqlAdapter
      require 'db_structure_ext/init_mysql_adapter'

      # This is an overridden implementation of the structure_dump so that the
      # rake take db:structure:dump will dump out the schema elements.
      def structure_dump
        connection_proxy = DbStructureExt::MysqlConnectionProxy.new(ActiveRecord::Base.connection)
        connection_proxy.structure_dump
      end

    end
  end
end

You need this so that Active Record actually extends the new methods. If you don't do this, then you can call "structure_dump" yourself in your code, independently for certain tables. But the new functionality won't come through as the default for all of your db tables unless you extend MysqlAdapter as per above.

Tuesday, 9 October 2012

Link: Women at work in Silicon Valley

Balancing work with family is one of the Hard Problems of Social Engineering a career... especially if you're female, and already suffer from several disadvantages in a high-tech workplace.

This article on The Guardian gives a great overview about how women in Silicon valley are making "Women at work" work.

Thursday, 27 September 2012

Link: Amazon Review-spoofing scandal

This is a lesson in how any system can be gamed.

Amazon reviews have been built up to be an integral part of how we evaluate books for sale on amazon. The ability to see what people are saying about a product has turned the process of book-buying on its head. Instead of briefly skimming the back of the jacket and taking a gamble on whether it's good or not, you can see the general consensus of the community of readers and *hopefully* get a better idea on whether this book is any good.

Unfortunately, like any process, it can be gamed, and this week we've seen how deep this can get.

A guy called Rutherford set up a review-buying service where authors could come and purchase good-reviews on amazon. In one case making a new author (John Locke) into an overnight millionaire.

Here's a link to the full story on the John Locke book review scandal

The uproar in the authorial world has been tremendous. and amazon are investigating what happened and what they can do about it. It's a tough job, because it's extremely difficult to figure out whether reviews are sincere.

Hopefully they can find a way because I'd hate to lose the ability to see the true measure of the community's feelings towards a book.

Friday, 21 September 2012

Link: count vs length vs size in Rails

Every now and then I have to remind myself of the differences between "count", "length" and "size" in Rails. I've never found a better source for this than the has_many :through article: count vs length vs size

It's well worth a read, even if you're an old Rails pro.

Saturday, 15 September 2012

make will_paginate always show matches/pages summary

will_paginate is the standard pagination plugin for many a Rails-2 site, and it's extremely flexible.

However it has one drawback: it will only show links - if there is more than one page.

This is mostly not a problem, if the links are all you show. But lets say you also use it to show the "Showing 26 to 50 of 342 matches" summary. Then lets say you want it to show "Showing 1 to 16 of 16 matches" - even when there's only a single page (for the sake of UI consistency). will_paginate does not provide an option for this.

There's talk of adding a :show_always => true option to will_paginate, but last I looked it hadn't been dragged into master...

So I wrote my own monkey-patch.

You'll need to put the following two snippets into config/intiializers/will_paginate.rb


The first thing you need to do, is make the "summary" sections public, so they are available to the renderer (which is the thing that generates all the page-links for you). Here's mine (both scavenged and adapted from the web many years ago):

module WillPaginate
  class LinkRenderer
    # generates eg: "1 - 15 of 15" or "26 - 50 of 342"
    def matches_summary
      if 0 == @collection.total_entries
        # because "0 - 0 of 0" is a bit much
        summary_text = "0 Matches"
      elsif 1 == @collection.total_entries
        summary_text = "1 Match"
      else
        summary_text = "%d - %d of %d" % [ @collection.offset + 1, 
               @collection.offset + @collection.length, @collection.total_entries ]
      end
      page_span(1, summary_text, :class => "summary")
    end    
 
    # generates "Page 4 of 62" or "Page 1 of 1"
    def pages_summary
      if 0 == @collection.total_pages
        # because "Page 0 of 0" is a bit much
        summary_text = "0 Pages"
      elsif 1 == @collection.total_pages
        summary_text = "1 Page"
      else
        summary_text = "Page %d of %d" % [ current_page, @collection.total_pages ]
      end
      page_span(1, summary_text, :class => "summary")
    end    
  end # LinkRenderer class
end # WillPaginate module

And this chunk is what makes will_paginate:

  1. Accept the ":show-always => true" option
  2. If the above is passed, and there are no page-links... displays the summaries
module WillPaginate
  module ViewHelpers
    # This lets us still use any will_paginate passed-in renderers if we want
    # adapted by code in original will_paginate
    def fetch_renderer(renderer)
      case renderer
      when String
        renderer.to_s.constantize.new
      when Class
        renderer.new
      else
        renderer
      end
    end

    # don't lose the old will_paginate
    alias :old_will_paginate :will_paginate

    # overload actual will_paginate call to allow us to choose to show the 
    # "number of matches" box even if there is only one page
    def will_paginate(collection, options = {})
      # strip out the show_always option
      show_always = options.delete(:show_always)

      # do standard pagination
      html = old_will_paginate(collection,options)

      # if we didn't get anything, but we have "show always" = true
      if html.nil? && show_always
        # set up the renderer (stolen directly from standard will_paginate)
        options[:container] = true
        renderer = fetch_renderer(options[:renderer])
        renderer.prepare collection, options, self

        # produce the "matches" boxes through the renderer
        links = [renderer.matches_summary, renderer.pages_summary]

        # generate the html for the pagination links - 
        # default the html-attributes to the plain pagination class
        html = content_tag(:div, links, (renderer.html_attributes||{}).merge(:class => 'pagination'))
      end

      html
    end

  end
end

Then you can call it with this:

   <%= will_paginate @things, :show_always => true %>

Monday, 10 September 2012

Link: 6 home truths about rockstar developers

We all want to hire a team of rockstar developers don't we? after all - with a team of rockstars our project will be the Best Thing Evar! ...or maybe not?

6 home truths about rockstar developers brings us back down to earth and points out the downsides of having a team formed of purely "rockstar" types. Worth a read - whether you're a hiring manager, or a rockstar yourself.

Saturday, 1 September 2012

validate_format_of with better test-names

validate_format_of is almost always called more than once on a single fieldname. Generally with different valid formats... and then with different invalid formats.

eg our set of date-format validations:

  # validate_our_date_format(:end_date, "Please enter correct format for end date")
  def self.validate_our_date_format(field_name,msg)
    # /^[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4}$/
    # dates we do match and should
    should validate_format_of(field_name).with('01/04/2010').with_message(msg)
    should validate_format_of(field_name).with('31/12/2012').with_message(msg)
    should validate_format_of(field_name).with(' 03/08/2010 ').with_message(msg)
    should validate_format_of(field_name).with('01/02/12').with_message(msg)
    should validate_format_of(field_name).with('02-01-2010').with_message(msg)
    should validate_format_of(field_name).with('1/2/2012').with_message(msg)
    should validate_format_of(field_name).with("04/10/2011\t\n").with_message(msg)
    # dates we don't match and shouldn't
    should validate_format_of(field_name).not_with('42/99/9999').with_message(msg)
    should validate_format_of(field_name).not_with('00/00/0000').with_message(msg)
    should validate_format_of(field_name).not_with('1').with_message(msg)
    should validate_format_of(field_name).not_with('abcd').with_message(msg)
    should validate_format_of(field_name).not_with('01/02/silly').with_message(msg)
  end

but there's a bug in validates_format_of... the description (which becomes the test name) is based on the following code: "{attribute} have a valid format" which makes tests named eg: "should :end_date have a valid format"... These test names are identical, not very useful, and not even properly grammatical.

*ALL* of them are named this eg, in the above example I'd have 12 tests all named as above...

At best, this identical-ness causes scads of Giant Flaming WARNINGS saying that
WARNING: 'test: <your enclosing scope here> should <fieldname> have a valid format.' is already defined
At worst, in certain (old) versions of rails - this means that only the first one gets run at all!

So - uniquifying the name is a Good Thing

The non-usefulness is that even if they do run, you don't know *which* version of your validates_format_of failed... because they're all named the same thing.

Thus this monkey-patch, which puts such things as the test-string *in the description*.

As with my previous shoulda backports, add these to a file in the config/initializers directory

module Shoulda # :nodoc:
  module ActiveRecord
    module Matchers

      # uniquify the description for validates_format_of "should" tests
      class NewValidateFormatOfMatcher < ValidateFormatOfMatcher
        
        # put a little more detail into the description
        def description
          if @value_to_fail
            "not accept #{@value_to_fail} as a valid format for #{@attribute}"
          elsif @value_to_pass
            "accept #{@value_to_pass} as a valid format for #{@attribute}"
          else
            super
          end
        end

      end
      # and override validate_format_of to use our new class
      def validate_format_of(attr)
        NewValidateFormatOfMatcher.new(attr)
      end
    end
  end
end

Note: this monkeypatch is for shoulda version 2.11.1 - not the latest Rails 3 version. You may need to modify accordingly if you're actually up-to-date...

Sunday, 26 August 2012

Rails: five year plan?

My workplace is putting a tender out to a government body, hoping to secure some work for a big development happening soon.

As part of the tender process, they asked us what is the five-year plan for the development of the Rails platform.

Keeping in mind that 37Signals' approach to planning is "don't - it's all fiction anyway", we still had to provide them with an answer... and this is what I came up with.


Asking for a five year plan is a question with a hidden assumption. What you *really* want to know is:

am I going to get stuck with a dead duck?

I think the nightmare scenario you're trying to avoid is that you'll get maybe 1-2 years down the line, have spent a lot of money on changing your system over to the new-fangled software, only for the Software Vendor to go bankrupt and leave you hanging in the air.

Suddenly you lose any support if things go wrong. Bugs are found, but you've got nobody to call to fix them and you certainly won't be seeing any new features. hackers might find a new security vulnerability and there'll be nobody on the front-line to patch that hole and stop them getting to your protected data.

You're in a bad, bad place.

Thankfully, this scenario can't happen with Ruby on Rails (RoR), due to its Open Source Nature.

RoR was originally developed by a company called 37signals - but unlike a proprietary product, 37signals doesn't own the codebase, because they gave it away to the community.

It takes a little while to wrap your head around how that changes things, and most people will instinctively think that this means less accountability, less power and less security - when actually the opposite is true... so bear with me as I compare this situation against what you might be used to with a proprietary vendor such as Microsoft's .Net

Microsoft own .Net they also keep all the code locked away so you can't see it and don't really know what goes on under the hood. They make all the design decisions, but they also make all the decisions about what gets fixed and when.

So, if you spot a bug in the code - you have to go ask Microsoft (nicely, and generally after waiting a long time on hold) to please fix it for you... If they say yes - it goes onto the end of a very long support queue for their team of developers to prioritise against all the other features and bugs they've had pour in over the last several years. and if they say no - you have no recourse. There's nobody else but Microsoft that can fix it for you.

You can complain about it - which will also get ignored.

If you have an SLA with them you can call and tell them to do it now... which *might* change their mind... but if things go sour - nothing on earth will persuade them to do anything. and your only recourse would be to take them to court...
and of course we all know that if it gets to court you've already both lost, you're just hoping to recoup some of the damages. Better to avoid the whole thing in the first place.

The short answer is that all the power lies in the hands of Microsoft, and you are reduced to a supplicant throwing yourself upon their mercy.

By comparison, RoR presents a very different picture.

As I mentioned before, 37signals doesn't own the code. If you have a copy of Rails, you do, and so do we, and so does everybody else that is using Rails.

This changes everything.

If 37signals goes bankrupt... there is still a huge community of people using (and contributing) to the development of Rails... and even if every single one of them goes bankrupt too - you still have a copy of it yourself. So if you need to fix a bug or patch a security hole - you have the code in your own hands and can do it yourself or get somebody like us to do it for you. Same thing for new features or even just customisations to make it work more like you'd wish it would.

The power-balance is radically different - you are the one with all the control.

Luckily I don't see 37signals going under any time soon. Rails was released in July 2004, and went 1.0 in 2005 and since then it has moved on from being an obscure platform used only by web-geeks and enthusiasts like me, to being enthusiastically embraced by a huge variety of businesses worldwide.

Rails has recently undergone a Major Upgrade with the release of Version 3.0 - totally overhauling and improving the structure of the framework to meet the ever-changing demands of the web world, along with security and performance improvements.

Meanwhile, Rails 2 is still strongly supported by the community - as many businesses are still using it, and it will continue to be supported until there is no-one left using it anymore This stands in stark contrast to the dire fate of obsolete Microsoft platforms - which Microsoft rigorously cuts off after a small number of months, stranding anybody left behind without support - or forcing them to pay huge re-licensing fees to upgrade to the newer version.

Rails is free, including all upgrades to new versions, so you can afford to stay on the bleeding edge as soon as you'd like to.

Even if 37signals drops support for an older version of Rails - the fact that the codebase is out there in the community means it remains alive and supported as long as the community remains. And that community is very big, and very active.

There are roughly 2000 active contributors to the rails-core codebase, including myself, and all of them are herded along by the rails-core team - a set of 12 developers, most of whom are currently employed full-time by 37signals to coordinate contributions.

What this means is that even if all of 37signals were suddenly wiped off the planet by a stray meteorite, there are still 1988 very active developers who are willing and able to continue developing the codebase... and not just minor enhancements and customisations of small side-features either, even my own contribution (while small) was a change to one of the fundamental core classes of Rails. While developers such as Yehuda Katz have overhauled the basic mechanics of the whole system (for the better, of course).
and there's nothing stopping you from making changes like this yourself at any time for the forseeable future - if you ever see a need.
Open Source means it's all available to you, all the time... forever.

Imagine trying to change something fundamental in one of Microsoft's products all by yourself... you wouldn't even get the chance because you don't have access to the code to even look at what's inside.

One final aspect that I'm sure is on your mind is security.

You're probably used to a big vendor taking responsibility for checking that the system is secure from hackers and fixing any security holes as they come up, and are wondering what happens with a scattered base of developers and code.

Again, I'll compare with Microsoft.
They're probably one of the biggest vendors on the planet, and they make a big noise about how secure their code is... and yet every week or two we hear about a new virus or worm exploiting a vulnerability in Windows.
Big Vendors make a big noise - but they actually can't guarantee security, however much they'd like you to think so.

So what can you get?

You can get an active community of developers continually testing the software for vulnerabilities and being responsive and timely in fixing any newfound holes.

and RoR has that in spades.

In fact, it's much better at it than an in-house development team like Microsoft. The reason being that shift in power-balance I mentioned earlier, coupled with the wider community base.

If a security hole is pointed out to Microsoft, it goes into the queue and *eventually* one of their developers gets a chance to look at it. Maybe it's fixed, or maybe Microsoft decides it's not important enough to fix because it's only affecting one customer so it's not worth their while... of course if that customer is you, then this decision is catastrophic, but given that Microsoft has all the power - there's nothing you can do about it.

With RoR, however, the power is all in your hands. You submit the bug-report to the community and chances are, somebody else is either experiencing the problem or also concerned about it affecting them. Given the size of the community, this means there's ten times the number of people available to fix the problem as with the in-house Microsoft developers team - and many of them are personally motivated to get the bug fixed because it affects their business too.

But even if nobody else in the world is affected by this but you - you can still get it fixed yourself - because you have the codebase, and you have access to developers that can get it done.
Something you simply can't do with proprietary code.

Far more likely, though, is that if you have a problem - then everybody else does too, so you announce the problem to the community, who picks it up and gets it solved and submits it back to the community for everybody to share... including you.

Sure, you don't have one company to smack with a stick if something doesn't get done... but you will actually find that you'll never be in that position in the first place - because there's always a better alternative.

and don't forget that with a bigger community - that's more people to find and fix bugs and security holes - before you even got to Rails in the first place. The Rails community has more collective eyeballs on the code than Microsoft can employ, and more eyeballs means more bugs spotted and therefore fixed.

So as a quick comparison:

Vendor-owned proprietary system: RoR and Open Source approach:
lock-in
- they choose when you upgrade
- restricted backwards compatibility
- you *must* upgrade or lose the software
Freedom
- you are free to upgrade when you want *if* you want
- it costs you nothing when you want to upgrade - you can afford to be on the bleeding edge
- support continues as long as people are using it
- or you can pay somebody to fix it for you whenever
They keep all the power
- bugs and holes are fixed when they want (or not at all) according to their own profitability
- features are only added if they think they can make a profit out of it
You have all the power
- bugs and holes are fixed by the community when they need fixing
- features are added on the fly by anybody that wants/needs them - you can add them yourself if you like
Security-by-obscurity
- only a few people get to look at the code, which means only a few people get to check that it works correctly. holes are more likely to be found by exploiters than by developers which means the first you hear of it is when somebody hacks your system
- holes are fixed if the vendor has time and only if they think it's worth the money they spend on it
Security through openness
- a hundred thousand eyeballs on the code means security holes are more likely to be spotted by developers and fixed before they even become a problem
- holes are fixed as soon as they become a problem - because the people fixing them are the people that are affected by the problem that are actually concerned about security rather than just the profitability.
Conclusion:
The software lives and dies with the vendor Even if the vendor dies, the community lives on and therefore so does the code. So you never get stuck with a dead duck.

Monday, 20 August 2012

shoulda: ensure_length_of.integer_field and associations with foreign key fields

We're still using Rails 2.3.X and therefore are stuck with thoughtbot-shoulda version 2.11.1 Which unfortunately doesn't come with a lot of the niceties of the most recent version. We've pulled some backports into our initializers directory to bring it up to speed - notably the ability to deal with foreign keys on association-definitions (see below).

But there's one small thing that has always annoyed me about shoulda - and isn't in any version.

That's the ability for ensure_length_of (the validates_length_of macro) to handle integer fields. Active Record can deal with it... therefore shoulda should too.

It's a tiny hack, but I'm currently too lazy to fork shoulda and write the tests to make it a viable pull-request, but here's a monkeypatch that'll get it working for you.

Save it into something like: config/initializers/shoulda_monkeypatches.rb, then use it like this:

   should ensure_length_of(:my_integer).integer_field.is_equal_to(4)
module Shoulda # :nodoc:
  module ActiveRecord
    module Matchers

      # I don't like it that ensure length of only works for strings.
      # This patch makes it also work for integers if we want
      class NewEnsureLengthOfMatcher < EnsureLengthOfMatcher
        def integer_field
          @integer_field = true
          self
        end      

        # re-write "string_of_length" to make the string an int-string
        def string_of_length(length)
          if @integer_field
            '1' * length # yep, this works for an int field
          else
            'x' * length
          end
        end
        
      end      
      # and override ensure_length_of to use our new class
      def ensure_length_of(attr)
        NewEnsureLengthOfMatcher.new(attr)
      end
    end
  end
end

Oh, and for the foreign-key backport:

module Shoulda # :nodoc:
  module Matchers
    module ActiveRecord
      # use the actual foreign key for an association
      class AssociationMatcher
        def foreign_key
          if foreign_key_reflection
            if foreign_key_reflection.respond_to?(:foreign_key)
              foreign_key_reflection.foreign_key.to_s
            else
              foreign_key_reflection.primary_key_name.to_s
            end
          end
        end      
      end      
    end
  end
end

Friday, 10 August 2012

Link: 10 things i hate about git

The more I use git, the more I miss subversion... my own head-slapping confusion atm comes from it's inability to do what I would consider quite a simple merge.

Exactly why does it create a merge-conflict for something like this:

class Widget < ActiveRecord::Base
  has_many :wodget
  belongs_to :product_image
<<<<<<< HEAD

  def to_s
    name
  end

=======
>>>>>>> master
end

Or even worse:

class Wodget < ActiveRecord::Base
  set_table_name :some_table_item
  
  has_many :invoice_items
  has_many :comments

<<<<<<< HEAD
  
     
  
  
=======
>>>>>>> master
end

I mean, really?

So in frustration, I typed "why is git so stupid" into the google bar (as you do), and came across this lovely link to 10 things I hate about git which resonates perfectly with my current mood.

Go have a look - they're all excellent reasons.

I'm sure git has many wonderful qualities, but right now, I'm not feeling the love.

Saturday, 4 August 2012

Link: vooza.com

"a mobile web app that is realtime, cloud-based, social and local... we're still in beta (have been for about four years now)... so we don't know what it does yet, but it will probably be like Pinterest or Instagram, but for weddings or sandwiches or something..."

vooza.com

Actually had me laughing out loud... I recommend watching to oldest-newest

"we prefer to think of revenue as a journey, not a destination"