Blog Archives

How to Get All Associations for an Activerecord Model

Posted in Inside TFG

There was a question that was asked on our IRC channel today about how to get all the associations for an Activerecord model. I’m assuming it was to do some debugging or something, in any case I did a bit of digging around in the Rails docs and it turns out the answer isn’t that hard.

Doing something like :

    Model.reflect_on_all_associations

Will give you all the associations for that model, it’s pretty dirty though and so an easy way to tidy it up is :

    Model.reflect_on_all_associations.collect{ |association|
        association.name.to_s.classify
    }

So, as usual with Rails it was easy as pie, I just am putting this here for future use :)

Edit : Thanks to Darcy for tidying up my previous mess :P

Entry to Graduate Medicine : The GAMSAT Day

Posted in Inside TFG

The Frontier Group is a collection of rag tag men, brought together from every corner, nook and cranny of the globe with the one common, purposeful consciousness. Usually this force is brought to bear on developing software that makes people cry less, and generally smile a lot more. Sometimes it’s just to win boat races at bucks parties. It’s a pretty well rounded and multi skilled force.

In any case, Frontiersmen (a term coined by one of our newest Frontiersmen) come from varied walks of life and experience and so besides working at The Frontier Group we also have outside interests. We place a high importance on learning and research and currently have a number of our staff undertaking post graduate and undergraduate studies. We have people donating their time to develop for charities and not for profits and those that act, DJ and all manner of other activities. We don’t just hire great people, we hire great people that are interested in being better tomorrow than they are right now.

So I decided that I wanted to be a doctor.

Last year I decided that instead of saying I’d like to be a doctor, I’d take the necessary steps to make it happen. I’d undergone something of a seachange in my life about six years ago and was starting to question if computing and IT was really what I wanted to do for the rest of my life. With that in mind and realising that for as long as I could remember I’d always wanted to help people, I started researching what I’d need to do to make it happen.

It turned out that with my engineering degree in hand I could actually sit a special test called the GAMSAT (Graduate Australian Medical School Admission Test) and after jumping through another half dozen hoops wearing a tutu, reciting some old english nursery rhymes, I could be a doctor four (short) years later. Slick!

GAMSAT Day

I sat the GAMSAT part way through March, and I thought I’d recount what it was like for the benefit of others. There isn’t a lot of information out there for people that want to know what how the GAMSAT day actually goes. Maybe it’s different from venue to venue, but I’ll just recount what happened to me.

The venue opened at about 8:15am for registrations. I’d heard this component could be a bit of a nightmare and upon rocking up and seeing about 400 people there I thought it was going to be terrible. However everyone there is nervous and wanting the same things you are. I think everyone was just in the zone and wanted to get in, and get settled. Registration was quick.

I stood in line for a while and shuffled through. I moved to the signup desk for my last name, handed over my admission ticket and some ID. The woman checked me off and gave me a card that said my desk number and room number on it. I then went and found a space to sit and just tried to relax. Mentally I felt relaxed, but physically I was in full stress mode.

I probably waited about 20 minutes before we moved into the room. You put your bags at the front of the room and keep your ID on you (you’ll need this a few times during the day) and get your pencils, pens and so on ready. I took a mechanical pencil, two pens an eraser and a 17 year old calculator; Many of the people sitting the test were about four to five years older.

You get a booklet of questions and an answer sheet you have to fill in with your name and some other details. Everything is very strict and they read a blurb about something and what you can and cannot do. Next thing you know you have 110 minutes to answer 75 questions about cartoons, pieces of text, poems, and so on. This stuff is hard. Like hair splitting hard. You really have to read the nuances of sometimes a couple of words used in a paragraph to choose between two very similar possibilities in the multiple choice options available.

In any case I finished the first section with about 15 minutes spare. It gave me time to change a couple of answers and just generally chill out a bit.

There were many times I could actually feel my heart pounding. Your head is so engrossed in just doing the test you don’t have time to feel the emotion of stress but your body definitely has all the time in the world to make it happen.

Straight after the first section is the essay component. I thought this would be my weakest area as you have limited time and space to get your writing done and I like to waffle a bit. I actually finished with about 20 minutes spare. The first part (it’s a two part section) was on censorship, the second was on self esteem and it’s relation to happiness and health. They were both right up my alley and I felt I did pretty well.

At this point you’ve been at it for just over three hours, so they give you a one hour lunch break. I went to my car, ate my lunch and relaxed for a bit. Lots of people had books out they were studying from but I just sat in the sun and tried to think about nothing. I figured an hour of study was less important than relaxing my mind. I was pretty drained already.

My suggestion though, bring your own food, drink and everything. The cafe still had a massive line by the end of the lunch break. The last thing you want is the stress of wondering whether you’re going to get anything to eat, or to go into the second part of the day without eating anything.

After lunch you sign in again and go back to your desk. The last part is three hours of multiple choice chemistry, physics and biology. By the end of this my mind was absolutely numbed.

In any case like I said most of the questions give you the back story, so for an organic chemistry process they’ll describe and show what happens and then ask you to extrapolate this to other reactions, or explain what might happen for longer chains and other reactions. You need some back knowledge and to know about most of the functional groups from first year chemistry but I found these questions to be absolutely fine.

The biology stuff relied on a tiny bit of anatomy knowledge and mostly understanding processes. You have to interpret a lot of graphics, figures and tables and sometimes also relate multiple figures to develop an outcome. You need to be able to store a lot of context about a situation. However I found the biology questions to be pretty easy and involved a mix of stats, logical interpretation and understanding the relationships between multiple diagrams or graphs.

The physics is really basic stuff, usually lenses or kinematic stuff. I felt like it was about as complex as some of the basic physics in upper high school so it wasn’t a challenge. I hadn’t studied any physics really except to familiarise myself with basic formulae and this was probably a wise choice.

I walked out feeling that this second science section was my weaker section because of the chemistry but I still thought I’d done okay. I just finished it in time and probably left with a few questions not complete.

At the end it’s actually quite anti-climactic. I’d studied a lot for the past couple of months, culminating in this day and now, after eight hours of stress it was all over, but I think I was just mentally exhausted. I went home, rang a friend, talked for an hour, did some shopping at the local grocer, ate dinner and went to bed.

So there it is, the GAMSAT. Results come in about six to eight weeks, but it was worth it for the experience. I think it’s like marathons for me, I’ve prepared for one and I’ve lined up for one but I’m not interested in doing any of the prep or event again if it doesn’t work out.

Results and Application
My results came in and the exam seemed to go better than I’d expected. My score put me in around the top 10% of people sitting the test which was surprising but cool. It’s a good start for gaining entrance into a medicine degree but it’s not the be all and end all, they take into account your previous university scores as well. Most courses now have a minimum university grade and a minimum GAMSAT score before they combine them to come up with your rank from the applicant pool.

Although my score in the exam was more than adequate, my previous Uni scores definitely weren’t. I applied to Notre Dame and UWA which both have minimum score requirements from your previous studies and I didn’t expect to get accepted to either programme. I got my results from applications some time in September and I was turned down for the courses I’d applied to. It was less of a let down than I’d assumed it would be, I think primarily because my job isn’t a bad one. I wasn’t running away from my job to study medicine, I was just being pulled towards the idea of being a doctor and taking care of people.

So that’s the journey of the GAMSAT. The study coming up to it is a whole other story, but that’s covered quite well elsewhere, I just thought some people may run across this post at some point and it would help them prep for the day itself.

How to Get Firebug, Capybara and Selenium Working Together

Posted in Inside TFG

I had an issue whereby a label I thought was fine wasn’t being picked up on my Cucumber tests. It turned out that the test environment was of course running our compiled javascript and I hadn’t compiled it since my change. The labels didn’t have the ‘for’ attribute specified so Selenium was whinging it couldn’t find the element I wanted to find.

In any case I couldn’t find an explanation of how to get Firebug working with Selenium and Capybara but after some doc reading I got my solution working so I thought I’d post it here.

In my env.rb file I have :

Capybara.register_driver :selenium do |app|
  Capybara::Driver::Selenium
  profile = Selenium::WebDriver::Firefox::Profile.new
  profile.add_extension(File.expand_path("features/support/firebug.xpi"))

  Capybara::Driver::Selenium.new(app, { :browser => :firefox, :profile => profile })
end

Specjour with Custom Bundler and Database Setup

Posted in Code, Inside TFG

We have a test suite here that now is rapidly approaching 2 hours using a single core. Let me just repeat that. A developer realistically would have to leave their machine testing overnight to see if the suite is working. That’s really not good enough.

Specjour has been a bit of a turn-key miracle worker with our RSpec suite, however lately we’ve started to require some custom database setup that we do in a seeds.rb file as well as some custom bundler install parameters as most of our devs don’t have MySQL installed. Both of our needs were being nicely stomped on by Specjour so I thought it was time to look elsewhere.

I took a trip down Hydra lane and while getting to the point of having a working, local, dual runner system was a piece of cake, getting something working remotely via SSH took me hours of pain. Debugging the remote SSH workers was a nightmare and I spent a couple of hours running through code before deciding it was probably better to update our existing solution rather than tooling up a brand new one.

Back to the Specjour code. Specjour includes a rails directory inside which is an init.rb which Rails will run at initialisation (it’s part of what Rails does) but the Specjour initialiser will always just run the default database setup task no matter what initialiser you’ve got setup. We had a specjour initialiser that runs if ENV['PREPARE_DB'] was populated, which it is by Specjour, the problem was that the Specjour initialiser ran in the Rails after_initialization hook and therefore stomped all over our database setup.

The first step was just to have our initialiser write to another ENV element and then to have the Specjour after_initialize handler respect this. This isn’t too hard to implement as the after_initialize handler is just a block that is attached and so inside of this block you just need to check that ENV element. In my case I created a new ENV['DB_PREPPED'] element when my database setup had completed and then when the after_initialize block runs it checks for ENV['DB_PREPPED'] and will do nothing if that’s been set to true.

Easy. I now had Specjour respecting our database setup task.

The next step was to try and test this outside of a Rails application, not only that but to test the operation of a block (anonymous function?). To do this I setup a stub on a mock Rails class and let it capture the after_initialize block and then I ran a number of specs against this block.

module Specjour
  module DbScrub
  end
end

DO_NOT_REQUIRE = true

describe "Rails Initialiser" do
  before :all do
    ENV['PREPARE_DB'] = "true"

    stub(Specjour::DbScrub).scrub

    class Rails
      class << self; attr_accessor :configuration; end
      class << self; attr_accessor :test_block; end
    end

    config = Object.new
    stub(config).after_initialize { |args|
      object = Object.new
      Rails.test_block = args
      object
    }
    Rails.configuration = config

    require 'rails/init'
  end

... tests ...

This code essentially mocks up Rails.configuration and then stubs the after_initialize method. This stub then places the block that after_initialize yields to into Rails.test_block. When I require 'rails/init' it sequentially processes the file (as with all Ruby) and the stub will capture the block. After this is a bunch of tests I run an whether the Specjour::DbScrub.scrub method is called or not, so it’s nothing special.

I felt like at this stage I had fairly well tested the main aspects of the database setup.

The next issue was with how bundler was being handled. We have a situation where we would like to install sometimes without some gems. Some of the gems we use and have written use applications we’d rather not maintain in development and get tested in our staging and production environments. We generally will run a bundle install in development without the production or metrics groups so I wanted to have the ability to pass through a custom bundler command. That’s pretty easy now with my gem. Inside .specjour/bundler.yml there is a command property. I think this is more complex than what’s required, but I can foresee us needing a number of custom rake tasks and shell scripts so this bundler.yml should have probably started life as a settings/commands/something_generic.yml

To test this part of my changes was pretty simple. I basically just stubbed the system calls to bundler to give certain return values and checked to make sure the correct program flow happened.

describe ".bundle_install" do
    let :manager do
      stub.instance_of(Specjour::Manager).project_path { "/tmp" }

      stub(Dir).chdir(anything) { |args|
        args.last.call # This yields to the block for Dir.chdir()
      }

      manager = Specjour::Manager.new
      stub(manager).project_path { "blah" }
      mock(manager).system('bundle lock')

      manager
    end

    it "should perform a bundle lock" do
      stub(manager).system('bundle check > /dev/null') { true }

      manager.bundle_install
    end

    it "should check if there are gems required" do
      mock(manager).system('bundle check > /dev/null') { true }

      manager.bundle_install
    end

    context "when gems are required" do
      before :each do
        # Not a before :all as it needs to hook into the let hook above

        stub(manager).system('bundle check > /dev/null') { false }
      end

      context "and there is a bundler YAML file" do
        before :each do
          config_file = ".specjour/bundler.yml"

          mock(File).exists?(config_file) { true }
          mock(File).read(config_file) { "" }
          mock(YAML).load(anything) {
            { 'command' => "do it" }
          }
        end

        it "should get the bundle command from the YAML file" do
          mock(manager).system('do it > /dev/null')
          manager.bundle_install
        end
      end

      context "and there is no bundler YAML file" do
        before :each do
          mock(File).exists?(".specjour/bundler.yml") { false }
        end

        it "should perform a bundle install" do
          mock(manager).system('bundle install > /dev/null')
          manager.bundle_install
        end
      end
    end
  end

You can see that I stubbed our the Dir.chdir block to just yield directly to the call, otherwise it’ll throw an exception. Then I stubbed and mocked out the Kernel.system calls as necessary. Kernel methods are generally included into Ruby objects so you don’t stub Kernel, you stub the object that has the Kernel methods. Most of the testing is pretty basic, but I’d be keen to hear if I’m doing anything incorrectly!

This was my first major venture into adding functionality to a public project and it was good fun. I think it made me do a little better work than I might normally, it’s a great motivation to potentially have peers look at how you do things.

After bundling it all up and testing it here with over a dozen developers and even more machines I’m pretty happy with how it functions. I’ve made a pull request back to the original gem creator and hopefully he’ll like what I’ve done. In the meantime if you want to check it out then my Specjour is available on Git Hub.

Parallel RSpec Performance Testing

Posted in Inside TFG

We’re currently deciding on hardware to build a bit of a testing cluster on which we’ll run whatever the current best remote testing package we can find. At the moment, for us, that’s ended up being Specjour. We ended up pitting one of our i7 iMacs against a $400 Acer box we bought. We installed Ubuntu’s REE 1.8.7 on the Acer machine and RVM and REE 1.8.7 on the iMac.

i7 iMac – Quad Core Hyperthreading

real 11m14.131s
user 0m0.776s
sys 0m0.348s

Acer – E5200 Dual Core E5200

real 35m56.658s
user 0m0.870s
sys 0m2.500s

It seems like the little Acer box offers slightly better value for money in this case. I’d like to see how we’d do with some virtualisation sitting on top this, but I think the included memory will be quite limiting in this regard. I wonder whether the processor resources are actually being fully utilised.

Twitter

The latest @rubyfive podcast is up, our own @sj26 receiving a mention for Ruby 1.9.3 performance improvements. http://t.co/hfx3EPMz

@frontiergroup about 1 day ago #

Search Posts

Featured Posts

Categories

Archives

View more archives