Starsigns & Dreams

March 7th, 2010 by Radar

Now I know that you guys expect this to be like… pure technological content since I’m a technological kind of guy, but sometimes I do break the rules. This is one of those more of a “blog” and less of a “tutorial” or “code” post. Sorry. Just something strange has been going on. Oh, and it contains profanity. Sorry.

I’m not one who believes in fortune-telling, I think it’s a complete and utter scam. These people will tell you precisely what you want to hear so they and their brethren can get precisely what they want: your money. They tell you all these good things and to pay attention to your horoscopes and star signs and so on and so forth, so you’ll go out and buy all these books about it and effectively dedicate your entire life to knowing about what’s going to happen in your future.

Fuck you.

No, really. Do you think that you’re such “a beautiful or unique snowflake” that the stars, balls of burning Helium, Hydrogen and whatever the fuck else are actually representing your fate? That they are able to correctly predict what will happen to you in terms of life (love and not), money and well-being? Jesus H. Christ you people are fucked in the head. You are not “a beautiful or unique snowflake”. Your fate is entirely dependent on your actions. If you want something positive to happen: work the fuck towards it.

Do not get me started on Numerology, either.

My (read: your) God.

Now that I’ve got that whole little blurb out of the way I can go on telling a story of two exceptionally strange coincidences that have happened within the past week. Yes, I view them as “coincidences”, not as “messages from the stars” or whatever you loonies want to call them. Although occasionally I feel that something is causing these to happen but then I have a nice hard-dose of a little thing us sane-folk like to call “Reality” and I’m right as rain.

Coincidence #1.

A girl at work asked me if my Paypal account had any money in it, I thought it didn’t but I checked anyway. There was some in there and she asked if I could use $1 for it to test some of the site’s donation functionality as it was misbehaving. I did, and it was. Then I thought that the money would be best out of the hands of Paypal and better in the hands of my bank so I “wrote” a mental note to transfer it when I got home. I didn’t.

That night I dreamed of a person or people putting money into my Paypal account. I quite often dream of things related to the previous day, almost like it’s a consequence of them being committed to my long term memory or something. So in the dream as I receive the money and go to transfer it, naturally I wake up. I always wake up from dreams when it gets to the good part.

So I get out of bed and onto my computer and as soon as I open up IRC I receive a IRC private message from Zarathu who says that he appreciates all my help that I give him and others and would like to show his respect in monetary format. He sends me $100.

Go figure.

Coincidence #2.

I have flu-like symptoms and to help me sleep through them I’m taking Codral day & night tablets. When I take the night tablets I have really, really vivid and sometimes whack(er than usual) dreams. Last night’s major consisted of myself and an unknown person really agreeing on something, we were having a discussion about something but there were no details. But we shared a common idea.

Tonight Marcelo & his girlfriend cooked dinner for us all and Marcelo’s mother came over. We talk about what I do and Marcelo’s girlfriend asks if I do iPhone development. I say that I tried to get into it but I needed an app idea in order to learn the language. She says she has an idea but she won’t tell me it because she fears I will steal it. There’s this one application I’ve been looking for (and I won’t say it because YOU will steal it :)) since the iPhone came out and I ask “Is it something to do with …?”

Silence.

“How’d you do that?”, she asks.
“Do what?”
“Read my mind.”

We spend the next hour talking about how awesome this idea is.

So, I still view these as coincidences, but for something like this to happen twice in a week is kind of freaky.

Testing Facebook

March 2nd, 2010 by Radar

We’re currently adding Facebook integration to an existing application that uses Authlogic. That means adding a button that any user can press on the login form that then takes them to Facebook, signs them in and then lets them log into our site. For this purpose and the time being “Facebook integration” means only that: letting the user login with their Facebook details. For the Facebook side of things we’re using Facebooker which is not the well-documented library we all would hope it is. Oh, and you cannot use it as a gem with Rails.

Also along with Facebooker we also use the Authlogic Facebook Connect plugin to provide us with a button we use on our login form. It also provides us with a file called xd\receiver.html in our public folder which’s use is documented here.

We created our application.html.erb using these key elements, as specified in the Authlogic Facebook Connect README:

<html>
  <head>
    <%= javascript_include_tag :defaults %>
    <%= fb_connect_javascript_tag %>
  </head>
  <body>
    <%= fb_connect_javascript_tag %>
    <%= init_fb_connect "XFBML" %>
  </body>
</html>

Our login page is nothing out of the ordinary save for this tag placed where we want the button to connect to Facebook:

<%= authlogic_facebook_login_button :length => "long" %>

As stated in the Canonical Documentation because we’ve generated the button the Javascript included into the layout will be executed when the user visits the page. This Javascript then calls the FB.init("YOUR_API_KEY_HERE", "xd_receiver.htm"); which does some Facebook/Javascript magic I am still yet to comprehend. This voodoo eventually renders a button that your user can click. When your user clicks this button it opens a popup window that asks the user to log into Facebook if they aren’t already, otherwise this will do a “seamless” login. We’ll go with the first option here and assume the user hasn’t logged in. But by the time you’ve read this, they have logged into Facebook and now the Javascript continues to execute, retrieving values from the popup window and stores them as cookies. After this is all “said and done” your form will be submitted and your app will carry on its merry way.

Here’s the beginning of our Authlogic-juiced User model:

class User < ActiveRecord::Base
  acts_as_authentic do |c|
    c.session_class = UserSession

    c.login_field = :email
    c.validate_login_field = false
    c.validate_email_field = false
    c.validate_password_field = false

    c.ignore_blank_passwords = false
  end

  # Store current user in the class so we could access it from the activity
  # observer without extra session query.
  cattr_accessor :current_user

  # Validations for email based accounts
  with_options :unless => :facebook_uid do |u|
    u.validates_presence_of :email, :message => :missing_email

    u.validates_presence_of :password, :on => :update, :if => :require_password?, :message => "^You must enter a password."
  end

  with_options :unless => Proc.new {|u| u.email.blank? } do |u|
    u.validates_format_of :email, :with => Authlogic::Regex.email, :message => "^The email given looks invalid, please check for typos."
    u.validates_uniqueness_of :email, :message => :email_in_use
    u.validates_confirmation_of :email, :message => "^The emails given did not match."
  end
end

As you can see here if facebook_uid is present we are not validating the presence of email or password for obvious reasons.

When your form is submitted it’ll go a create action in a controller (we called ours UserSessionsController) and looks like this:

class UserSessionsController < ApplicationController
  before_filter :check_fb, :only => :create
  #...
  def create
    @user_session = UserSession.new(params[:user_session])

    if @user_session.save && !@user_session.user.suspended?
      unless @user_session.user.facebook_uid.nil?
        @user_session.user.active = true
        @user_session.user.save
      end

      flash[:notice] = t(:msg_welcome)
      if @user_session.user.login_count > 1 && @user_session.user.last_login_at?
        flash[:notice] << " " << t(:msg_last_login, @user_session.user.last_login_at.to_s(:mmddhhss))
      end
      redirect_back_or_default root_url
    else
      #...
    end
  end
  #...
  private

    def check_fb
      if params[:user_session].nil?
        ensure_authenticated_to_facebook
      end
    end
end

We have specific code here to activate a user if they log in through Facebook; we assume that if a person is logging in through Facebook that they are not an automated robot (as opposed to a manual one?) and they do not need a confirmation email sent. What’s most exciting about this code however is not the create action, but the before_filter we run… erm, before… it.

As you can see, the before_filter calls ensure_authenticated_to_facebook which is a method from Facebooker, traditionally used itself as a before_filter but because we have the ability to log in with an email & password OR a facebook login, is called conditionally. That method looks like this:

def ensure_authenticated_to_facebook
  set_facebook_session || create_new_facebook_session_and_redirect!
end

This attempts the set_facebook_session method first:

def set_facebook_session
  # first, see if we already have a session
  session_set = session_already_secured?
  # if not, see if we can load it from the environment
  unless session_set
    session_set = create_facebook_session
    session[:facebook_session] = @facebook_session if session_set
  end
  if session_set
    capture_facebook_friends_if_available! 
    Session.current = facebook_session
  end
  return session_set
end

We do not have a current session so it’ll go and call create_facebook_session:

def create_facebook_session
  secure_with_facebook_params! || secure_with_cookies! || secure_with_token!
end

So this uses three methods: secure_with_facebook_params!, secure_with_cookies! or secure_with_token. Remember what I said earlier about what happens when the user presses the button? No? Here’s a refresher: it sets cookies. Not the edible kind, sadly. So the method that’ll be used here is secure_with_cookies!.

I feel now is a good time to show you the test we wrote.

describe UserSessionsController do
  describe "create" do
    describe "facebook user" do
      it "creates account based on facebook details" do
        FakeWeb.allow_net_connect = false
        FakeWeb.register_uri(:post, "http://api.facebook.com/restserver.php", :body => Rails.root + "spec/fixtures/get_users_info.xml")

        setup_fb_connect_cookies

        post :create

        response.should redirect_to(root_url)
        @assigned_user = assigns[:user_session].user
        @assigned_user.new_record?.should be_false
        @assigned_user.active.should be_true
      end
    end
  end
end

We first disable internet connections using FakeWeb. We do this so we can stub out the response to Facebooker’s internal call to getUsersInfo to Facebook and always return a valid user object. The fake XML can be viewed in this gist.

After Fakeweb has done its thing we call the setup_fb_connect_cookies method which does exactly what it says on the box, it lives in the spec/support/facebook_helpers.rb file:

def setup_fb_connect_cookies
  cookie_hash_for_auth.each {|k,v| request.cookies[ENV['FACEBOOK_API_KEY']+k] = CGI::Cookie.new(ENV['FACEBOOK_API_KEY']+k,v).first}
end

def cookie_hash_for_auth
  hash = {"_ss" => "not_used", "_session_key"=> "whatever", "_user"=>"77777", "_expires"=>"#{1.day.from_now.to_i}"}
  raw_string = hash.map{ |k,v| [k.gsub(/^_/, ''), v].join('=') }.sort.join
  actual_sig = Digest::MD5.hexdigest([raw_string, Facebooker::Session.secret_key].join)
  hash.merge("" => actual_sig)
end

Why such complicated code? Well, this provides the cookies that Facebooker needs in order to log in. The final three lines in the cookie_hash_for_auth method is all about setting up a “signature” which Facebook parses in the parameters to ensure that they haven’t been tampered with. The generation of this was ripped straight from the guts of Facebooker which uses (almost) the same code to generate an MD5 to verify the signature against.

In short: We now have cookies that our post :create is going to use. So, when this is triggered secure_with_cookies! does its thing:

def secure_with_cookies!
    parsed = {}

    fb_cookie_names.each { |key| parsed[key[fb_cookie_prefix.size,key.size]] = cookies[key] }

    #returning gracefully if the cookies aren't set or have expired
    return unless parsed['session_key'] && parsed['user'] && parsed['expires'] && parsed['ss'] 
    return unless (Time.at(parsed['expires'].to_s.to_f) > Time.now) || (parsed['expires'] == "0")      
    #if we have the unexpired cookies, we'll throw an exception if the sig doesn't verify
    verify_signature(parsed,cookies[Facebooker.api_key], true)

    @facebook_session = new_facebook_session
    @facebook_session.secure_with!(parsed['session_key'],parsed['user'],parsed['expires'],parsed['ss'])
    @facebook_session
end

This has now generated a value for session[:facebook_session], a Facebooker::Session object. Great. The @user_session in our controller has a user method that returns a valid user and we ensure it’s that way in the remainder of the controller test. Great, so that part works. Now about how doing something with the logged in user?

Well for that purpose, Elad Meidar wrote a blog post covering how to do it in Cucumber. This consists of setting up your facebooker.yml to having a cucumber key share the configuration of the development key and a couple of steps:

Given /^I am logged in as a Facebook user$/ do

  # Initializer facebooker session
  @integration_session = open_session

  @current_user = User.create! :facebook_id => 1

  # User#facebook_user returns a Facebook::User instance, i decided to mock the session in here since i am not
  # sure what the behavior might be if it will be in the actual model.
  @current_user.facebook_user.session = Facebooker::MockSession.create(ENV['FACEBOOK_API_KEY'], ENV['FACEBOOK_SECRET_KEY'])
  @current_user.facebook_user.friends = [ Facebooker::User.new(:id => 2, :name => 'Bob'),
    Facebooker::User.new(:id => 3, :name => 'Sam')]
  @integration_session.default_request_params.merge!( :fb_sig_user => @current_user.facebook_id, :fb_sig_friends => @current_user.facebook_user.friends.map(&:id).join(',') )
end

This code sets the parameters on the next request and Facebooker accepts these and uses them to create a new Facebooker::Session object, which it stores in session[:facebook_session].

The open_session method comes from Facebooker by placing this line in features/support/app.rb:

require 'facebooker/rails/cucumber'

The facebook_user method on our User object comes from defining it on the User model:

Now with the steps and correct requires in place, we have our feature:

Feature: Facebook
  In order to use the site as a facebook user
  As a user
  I want to have already logged in with Facebook and be roaming the wide brown lands

  Scenario: logging into facebook
    Given I am logged in as a Facebook user
    And I am on the homepage
    Then I should be on the homepage

This is just a silly example that ensures that the user is not redirected back to the login page if they are logged in as a Facebook user. I hope you write better features than this. This feature will fail for the time being because our current_user method only queries current_user_session, so we’ll modify it to be this instead:

def current_user
  @current_user ||= (current_user_session && current_user_session.record)
  @current_user ||= User.find_by_facebook_uid(session[:facebook_session].user.uid)
end

Now we can use current_user to reference current Facebook users too, meaning our feature will now pass.

With a controller spec and feature passing, that’s lunch!

For After Lunch

So how was lunch? I hope it was good. Since this is only a one-way kind of communication I can’t accurately respond to whatever you’re going to say. Sorry!

Right then! So our application is tested well enough that we know that we can log in using faked-out Facebook cookies, but does the actual real-world side of things work? Does clicking the button actually prompt the user to log into Facebook if they haven’t already or just go through that whole section transparently and present them with an already logged in screen?

Chances are this is a big, gigantic, fat

No.

You’ll more-than-likely run across an “Invalid parameter” issue as we had when we tried to use our application. The error code for this is 100.

So what’s up?

Well, as it turns out, when you try to go to the login page for an application that hasn’t yet been activated it just warns you that it hasn’t been activated. I’m not quite clear on how Facebooker works in this particular section, but it is my understanding that the login page is supposed to take you to the application page. Let me explain in step-by-step kind of way. “application’s page” means your site in this scenario. You’ve set this up by specifying the “Connect URL” in the “Connect” section of your Application Settings page to be the root-level of your site. So this is how Facebooker does its thing:

  1. Facebooker grabs an auth_token using the facebook.Auth.createToken API method. This returns something like 72a910e1f24eb6034549d23cd2245f28
  2. This auth_token is then passed to http://facebook.com/login.php as a parameter, which is rendered in whichever fashion you wish. For all intents and purposes, our application renders it in another browser window.
  3. The login.php page detects if you are logged out or in and does either:
  4. If you’re logged out of Facebook, prompts for an email and password. If you “get this right”, Facebook sets up some cookies, links that auth_token to your Facebook user, and redirects you to the application.
  5. If you’re logged in to Facebook, Facebook sets up some cookies, links that auth_token to your Facebook user, and redirects you to the application.
  6. The cookies are then used to call facebook.Auth.getSession which, because you’re now most-definitely logged into Facebook, will return a session object. Something that looks like:

    2.5KVyRHmZWBbOun8ZwDwQxg__.3600.1243290000-608966587\n  608966587\n  1268190000
    

  7. Facebooker creates a Facebooker::Session object based on this return value which it stores in your application as session[:facebook_session]
  8. What could possibly go wrong is that if you have your application in “Sandbox Mode” (under “Advanced” in “Application Settings”), when you go to the login page you’ll be shown the “This application is under construction” and therefore Facebook will not link your user account with the auth_token so when facebook.Auth.getSession tries to do what its name implies: it’ll fail with “Invalid Parameter”. Just be careful about that! It had us caught up for a day and bit, we didn’t know about that option.

    I hope you found this as informative as I found it interesting to investigate.

Congratulations

February 13th, 2010 by Radar

Congratulations! You’ve worked so amazingly hard over the last seven-and-a-half months on this project. You met all the client’s demands as they came in. You completed the project on-time and under the $30,000 budget by $2,000. The client is pleased about that. You can tell by the dollar signs in his eyes. The client is also pleased that they’re able to put the website out to the world to grow and conquer it, it already has a couple of users from the beta invites you sent out earlier in the week. You still keep in touch with the client on an almost-daily basis. He’s saying the site’s doing great.

But.

There’s this one user who’s reporting an issue with a feature you worked on 3 months ago. The client has set up his personal email address to receive the bug reports. You receive them when he gets around to sending them. The page is showing “We’re sorry but something went wrong”.

Uh oh.

You log into the website and check for yourself. Sure enough that page is throwing a 500. But why? This feature was completed 3 months ago and worked fine then, didn’t it? You try it on your local machine and you see that it’s something simple. Perhaps a variable incorrectly spelled in the controller. Or perhaps not. Perhaps it takes you longer than a couple of seconds to identify the issue. Perhaps it takes you an hour, a day.

A week.

So how did this error come to be? You did write tests, didn’t you?

Oh I see.

Because of the impending deadline you were pressured for time and couldn’t be bothered learning any of the testing frameworks. Your boss says “The client’s not paying you to write tests, he’s paying you to write features” when you bring the point up. Even though your Rails knowledge has increased during the life of this project three to four times the size of what it previously was, you still don’t know shit about testing. Maybe’s the time to start to learn you think. Ah, but The Boss doesn’t want you spending time not producing features. “Tests are a waste of the client’s money” he claims. You sigh. “I’ll do the next project better. I’ll get him to see the light.”, you say in your head. Ok, so you didn’t write tests. I’m sure you can use git bisect to go back through the revisions and see which one broke it, right?

Oh I see.

You use SVN. That’s fine too. You’ll just have to find another way to go through each revision and find which one broke it. I’ll see you tomorrow when you’re getting close to that goal. Maybe next Wednesday you’ll figure out that it was r348 that broke it, the current trunk is r2343. Have fun with that.

You fixed it. The bug is defeated, sent to the depths of Hell along with one eighteenth of your sanity. That was quite a toughy. You did write a test to ensure that it wouldn’t happen again, right?

Oh I see.

You commented on the Basecamp todo item saying that it was fixed. I guess it has a searchable name, right? Just in case it comes up again? It’s called “Something went wrong”?

Uh oh.

So you go home, satisfied that you kicked the ass of a bug that had been on your mind for days. You win.

Congratulations.

The next day you wake up, grab your coffee/milk/orange juice and check your emails. There’s 3 from Facebook, a couple from a few mailing lists you subscribe to and fourteen from your client. These aren’t fourteen love letters. You see the first one was sent to you 20 minutes after you went to bed. If only you had stayed up later. You will tonight, just that extra 20 minutes since that’s when the client comes online.

You read the first one. It’s a bug report. So is the next one. And the one after that. And the one after that. And guess what? The one after that, too.

All fourteen emails your client sent to you overnight weren’t “Thanks for all your fabulous work on the site” they were the “Why the fuck is this shit broken?” kind of language. He paid good money for it he thinks. You are happy being paid $20/hr. It hasn’t been long that you’ve been doing this anyway and you have to start out somewhere.

Congratulations.

You now have bug reports to deal with when you get into work this morning. 8 hours in a day, with each bug taking you 30 minutes to do. Easy, with time to spare. “Pfft. Done by sundown”, you think. You realise that one of the bug reports that got sent in was that bug that you fixed the other day. Another developer working on your project had a conflict with the file and accidentally put back the broken code instead of the working code. Ok. That’s fine. You’ll fix that one too. You have a 2hr meeting with another client at the beginning of the day, leaving you with only 6 hours to fix those bugs by sundown. You spend an extra half-hour at lunch. Five-and-a-half-hours. But by lunch you’d already “killed” four of them. You were a bit groggy this morning and you think that lunch will cure that feeling. You’ll conquer the other ten this afternoon.

You don’t.

You finish four, maybe five of them leaving eight, maybe nine bugs fixed. The client is not pleased. You have only done some of the work. He expects a 7-day-a-week-24-hour-all-the-freakin’-time response.

Because you’re his bitch.

Alright. So your boss gives him a large apologetic email that you will try harder in the future to meet all of his demands because you don’t want to lose this client. He’s invested $30,000 in this company already and with “Version 2″ of the site “just around the corner” he’ll probably invest a lot more.

So you’re back to fixing those remaining bugs. During the night another three have come in. Your bug count is now eight. Eight hours in a day, eight bugs in the list. Done by sundown. You complete seven. You’re exhausted. They took you all day to debug. You email the client and say that you’ve only fixed seven of the eight bugs. He emails you back, naturally twenty minutes after you’ve gone to sleep saying that the eighth and final bug “makes the site unusable”. Your boss brings you in in the morning and says that your work isn’t good enough. You baulk at this suggestion. You claim to have fixed thirteen of the fourteen bugs the client emailed you earlier in the week. Today you’ll have completed the fourteenth one, you’re so confident about that. He naturally asks why there were fourteen bugs in the first place. You don’t have an immediate answer. He continues on his rant about that you should be testing the code each time you deploy it. Go through the site and make sure that it’s ok. The boss continues on his tirade for an hour. You try to counter his arguments but you view him as some sort of “higher-being” and due to your lack of experience you can’t fault him. He’s the boss man after all. He got there somehow.

Your company has accrued all this technical debt that you didn’t budget for. This carries on for a month longer and now the client has gone over his budget by $2,000. $2,000 he never wanted to spend. He’s talking about leaving your company and moving to another one who could do a better job. This is probably the case. Your boss brings you in and tells you what’s what with this project. The client is leaving. The next day he fires you.

Congratulations, Freebird. You’re out of a job and very, very nearly out of money. A couple of grand is all you have left. Time to begin that hunt again.

So how do you prevent something like this from happening?

You eventually get a new job working with a new company. You sit down with your new client and you do it right. You spec out their application using something like Pivotal Tracker. You write tests religiously for every single story in Cucumber. There isn’t a story without a test. This reduces technical debt in the long run. You won’t have as many bugs like you did when you didn’t test with the previous application. You will have bugs, though, but you won’t be spending those long nights fixing them because you have tests covering it all. The tests will show you where something went wrong because more than likely, a broken part of the site also means a broken test.

So you start off on a simple story such as “User login” and you write a cucumber feature for it with two scenarios. One for logging in. One for logging out. You’ve written all the steps for it but some of them are not implemented, others are just plain broken. That’s because you haven’t written any code for it yet. This is called Behaviour Driven Development. You’re going to be learning it, and you’re going to do it right from now on. You implement each step one at a time and eventually your feature is all green. Why do you do this? So future-you doesn’t come back in 3 months and see that this feature is broken. Bonus points if you’re using a Continuous Integration server to ensure that this feature and its eventual brothers stay green. A broken build means a broken application and your goal if that build is broken is to make it very, very unbroken.

Congratulations.

You can now mark that story as “Finished” in Pivotal. Then you can deploy it to a staging server and mark it as “Delivered”. The client then can log in to Pivotal and see that the story is marked as “Delivered” and then log in to the staging server, test that feature and press that “Accept” button. You want to be seeing green stories in your Pivotal list. Green is the colour you want to be seeing everywhere.

So the next feature comes along and involves some rather complex controller logic that returns a JSON hash. You can write this also in Cucumber, or you could write an RSpec Controller test. Either way, you’ll write the test first and then the code. Then it’ll pass. Then you can refactor the code (unless you write awesome code (hint: neither of us does.)) and it’ll still pass. Sure it will feel slow at first, but that’s because you’re learning how to do it. Don’t fight it. It will save you a lot of time in the future, where it’s most important.

Eventually after the next seven-and-a-half months you’ll have all these Pivotal Tracker stories all green in the “Completed” section and maybe one or two in the “Backlog” that the client wants done for next release. You’ll run all the specs on your system. They’re all green. You’ll run all the features. They’re all green. You deploy to the staging server for the last time for this release. The client loves it. You deploy it to production and send out the invites. Everyone loves it.

But.

There’s a bug. This time however you’ve installed something like Hoptoad so in your inbox you’ve got the error there. You are the support team for this application. After all, you’re still working for a small company. It contains stacktrace and you can see where it went wrong immediately. You write a test/feature to ensure that this bug would never happen again. It fails because you haven’t fixed the bug. The error is the same one as in the Hoptoad email. You fix the bug.

Congratulations. You’ve successfully regression tested a bug. This bug never happens again for the life of the project.

The client is happy. Your boss asks if he can have a chat with you. You’re doing an awesome job. The other guys were previously on a higher salary than you. Now you’re equal. The client wants more work done on his application. He’s flying your boss to America next week. They’ve specifically requested you to go along too, as you seem “switched on”. Later on in that month, the client invests a 7-digit fund into your company. It grows. Massively. You bring on another ten guys over the next year just to work on this application. You and a couple of the other “Originals” teach them all you know about your application and the process you’ve helped develop. They then go on to teach the other twenty people you hire in the six months following.

Congratulations. Now you’re doing it right.

The Initialization Guide

February 8th, 2010 by Radar

For a couple of weeks now I’ve been writing a guide on how the initialization process in Rails 3 works. As of writing, the guide and its accompanying “notes” totals over 10,000 words. I admit that this is currently nowhere near completion, but I am working on it and I need your help. I need people to go over it for me and point out anything that they don’t quite understand or I have stated incorrectly and file an issue on the repository for it. Originally I was going to accept pull requests but they aren’t “public knowledge” and I don’t want two or more people submitting pull requests to fix the same chunk of code. With issues, people can see that “oh, there’s already a typo here.” and move on to finding more errors and punching more holes through it.

So yeah, if you guys could read my guide and file any issues you find with it, that’d be swell!

Computer Woes

February 1st, 2010 by Radar

Today I had to deal with two Windows-based computers’ problems for Mark and Marlene. Here’s what happened.

Mark

Mark has a 4 year old Compaq Presario f500 which occasionally when you switch it on it’ll keep rebooting itself without showing anything on the screen. The fix for this was to turn it off, leave it off for a couple of seconds and then turn it back on. Then the problem went away until you turned it off and on again, in which it would resume. I couldn’t figure this one out. The other problem Mark had with his computer is that when he left it alone the screen would go strange. We figured out this was his screensaver, and changing away from the “Pictures Slideshow” option fixed it. I suspect there’s something in there that isn’t quite right.

Marlene

Marlene’s daughter has a recently bought no-name-brand case with a no-name-brand motherboard in it. Marlene had the computer at her house because she told me about the issue last night and I couldn’t fix it over the phone and her house is easier to get to than her daughter’s. The issue was that the computer wasn’t getting past the first POST screen, the one with the CPU & Memory information. I opened up the case when I got to Marlene’s house and saw that the cable for the CPU fan had a tiny cable tie clip on it that was stopping the CPU fan from spinning. Apparently this stops the computer from getting past that point! I moved it out of the way and tucked it around some other cords to make sure it wouldn’t get in the way again, sealed the case and tested it, it worked and so I thought that was that.

Until 5:30 tonight.

Marlene phones me up. The computer’s making a beeping noise. I can hear it in the background, “BEEEEEEEEEEEEEEEEEEEEEEEEEP”, pause, rinse, repeat. One long beep. It wasn’t doing that earlier. So I trek as far north in Brisbane as I have ever gone to play around with this box. I needed to fix this problem as I felt it was something I did. I get there and sure enough it’s making the “BEEEEEEEEEEEEEEEEEEEEEEEEEP” noise. I take the side off the case and the cord for the CPU is where I put it and that fan’s spinning alright.

I looked it up on Wikipedia and it said that it could have been a memory issue, so I took that out. No change. I took out the graphics card. No change. I took out the sound card. No change. I unplugged the power and data cables to the harddrives and DVD drives. No change.

What the hell?

I was on the verge of giving up so I just put everything back in the case one thing at a time, starting with the graphics card.

CHANGE!

The computer emitted a singular quick beep indicating successful POST and a choir of angels was heard in the distance.

Pieced it all back together and it booted fine. Did the ol’ go-through-and-remove-all-the-spyware-shit-that-builds-up routine and another happy customer!

tl;dr:

  1. Wacky screen after a period of non-use? Try changing your screensaver.
  2. Long singular beep? Ensure the PCI cards are seated correctly.

Why Mocra Is Awesome

January 21st, 2010 by Radar

Mocra is awesome because their employees are some of the brightest and most “switched on” people I know. They come up with fantastic ideas and execute them brilliantly. They even sometimes allow their employees to work on open source during work hours. Putting that much brainpower into a company that small is a genius idea. Yes, they’ve struggled. But what small business doesn’t? It’s still in its early phase and they’ve refined their process down to a tee and are really getting their stuff together. I fully support the company and will remain friends with them all. If you’re looking to hire a Rails company for your new/existing Rails application, hire Mocra.

Now to being completely honest with everyone.

I’ve decided that I want a change. As of today, I am no longer employed by them. I’m not sure how to phrase what went down. I got angry, and left. This had happened before. Later Nic called and asked me to come in to have a chat the next morning. This is entirely my fault. I wanted to leave for a while, to explore what else is out there. With freelancing, I got that power to travel and work with different people. I know the whole “grass is greener” cliche, and I’m aware of that. I need something different, perhaps to only focus on one project instead of multiple at a time? I’m not quite sure. Freelancing was fun, but it’s also very, very lonely. I’ve had a couple of leads but I think it’s too soon to be jumping into another job. I need to realise that, attitude wise, I need to change it. I’ve changed it since NetFox quite a lot with some of that due to a little book called “How to Win Friends and Influence People” by Dale Carnegie. The suggestion to read this book came from no other than Dr. Nic himself. I read it and realised there were some things in there that I wasn’t doing and that would not only improve my life, but the life of the people around me. It did exactly that.

One thing the book does not have a chapter for is anger. When we went to the Ski Trip at Thredbo I got angry with a waitress because I wasn’t served a steak. Everybody else’s order came out, and mine was simply lost in the process. They made a mistake, and I got angry for no real reason. The waitress apologised but the mistake was done! How dare she stuff up my order! She’s supposed to be a professional. I could put this down to the fact that I was tired, but that should not be used as an excuse. As long as I have the ability to breathe I should have the ability to be polite and analyse a situation before showing my emotional response. This is what I need to continue to refine. There’s no showing you how much I’ve improved since the school days, since Netfox, I can only state that I have.

And only yesterday did I lash out at Bo. I had just received an email for my car damage. I had scraped the side of it and destroyed the right mirror by reversing along side a pole at a shopping center. I was angry at myself then, and that level of anger I believe was acceptable for that situation. I made a mistake, and it was going to cost me money. The email said the repair and the service was going to cost $1,500! I tried to bottle it up and shrug it off, but it ate away at me inside. $1,500! GONE! For what? Shortly after I was writing a bash script to change the keymappings for a plugin Mocra uses called Telefrag. This plugin works with Teleport and allows me to type in QWERTY when Bo or Chendo is typing in Colemak or Dvorak respectively, dismissing the need to switch keyboard layouts with a shortcut. The script wasn’t working as I wanted it and Bo suggested something whilst I was trying something else, and I said something angrily at him. This is an unacceptable case of showing my anger, and therefore I failed, again. I was not angry with Bo and he’s not the one who cost me $1,500. It was me. Getting angry like that cost me my job and I fear could cost me future employment opportunities and eventually leave me in a worse state than where I am at now. I need to stop getting angry so easy and over such trivial things. I need to learn how to.

Mocra is awesome, I failed them and am now unemployed again due to my, and only my, actions. I will fix this, I promise you. This post needs to exist so that people can show it to me, remind me of it, snap me out of it. I will always remember how bad I felt writing it, but also how much of a relief it was to get it off my chest. Yeah, future employers may see this. At this specific point in time I am still human, and therefore still have emotions. This is me describing my journey of controlling them for self-betterment.

Thanks to those who have offered their support over the past 24 hours (friends & family), you have all been brilliant and without such a group I would have probably done something drastic. If you guys ever need anything, I am always available for a chat, as you have been for me. I don’t care if it’s 4am. Call me if we need to talk. I’m there.

Seriously, hire Mocra. They have been fantastic, and I know that they have, can and will succeed.

Ruby 1.9.1 & Friends: 11 Months On

December 5th, 2009 by Radar

I admit that the title would be cooler if this were “1 year on” but I couldn’t wait. Sorry.

Back in January I wrote a post about installing Ruby 1.9.1 on my Mac OS X box and the issues associated with it. The “end goal” was to get rboard running on it under passenger. This was painful back in January! It’s so much easier now!

Unfortunately, there’s still this bug which effects you if you’re on Passenger and 1.9.1. There’s a patch for one of the answers there and that’ll get your application working, but I’m of the belief that you should not ever have to patch a gem and especially the Ruby source.

I want to know: Have you tried running your app on 1.9? Have you encountered any showstoppers?

Quite a lot has changed since January and I’ve decided instead of updating that post, I’m going to go through the entire process again. This is because I would like to show how far Ruby has come during the time since I have written and updated that post and that running your application on Ruby 1.9.1 isn’t as much hassle as people make it out to be.

This time I will be installing it all on an Ubuntu box, since that’s more than likely the location where you’re going to be deploying your app’s code to. I’ll be using Ruby 1.9.1p243 and Rails 2.3.5.

For those of you who don’t like long blog posts here’s the script if you want to install everything without reading through the cruft. Running this script or bash -c “`wget -O – frozenplague.net/boris`” on your server will install the bare-basics:

  • git (latest version)
  • apache 2
  • mysql 5
  • ruby 1.9.1
  • rails (latest gem version)
  • passenger (latest gem version)

Then you’ll be able to setup your Rails app. I can’t do that for you, sorry. My scripting-fu is not that good.

Thanks to Ben Hoskings for the inspiration for this script.

The Long Road

To install Ruby 1.9.1 from source on a base Ubuntu system there’s a couple of pre-requisites. Let’s cover why they’re required.

build-essential

Includes stuff that is, well, essential to building things, like Ruby and the other dependencies.

libssl-dev

Needed for when we go to install Passenger. If not installed you’ll get no such file to load -- openssl because Ruby didn’t install openssl because this dependency was not installed. Fun times were had.

libreadline-dev

Needed for launching script/console. It’ll complain no such file to load -- readline when trying to launch it.

zlib

When you go to sudo gem install rails you’ll get no such file to load -- zlib. This error message is not helpful but it means you need zlib1g installed: sudo apt-get install zlib1g-dev

Now you’ll be able to download and install ruby:

mkdir ruby
cd ruby
wget --progress=bar ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p243.tar.gz -O - | tar -zxf - --strip-components 1
./configure
make
echo "Need your password to install Ruby:"
sudo make install

And then finally your gems:

cd ~
sudo rm -rf ruby
sudo gem install mysql passenger rails
sudo passenger-install-apache2-module

I needed to patch Ruby + Passenger with this patch, as when I went to log in to rboard it gave me the error at the top of that page.

Other than that, all of this works perfectly fine on my bare-bones Ubuntu box. I was even able to get rboard running on this setup!

So again: Have you tried running your app on 1.9? Have you encountered any showstoppers? Really keen to hear your stories!

A Day Without Talking

November 23rd, 2009 by Radar

So I’ve just been to yet another fantastic Railscamp over this weekend and I really enjoyed myself. Well done to the organisers.

As per tradition, however, I have come down with yet-another throat related issue, this time I suspect (using my e-doctor skillz) it’s Laryngitis. On Saturday it was a little bit of effort to speak but I could still do it, yesterday was slightly more effort and today… well: I was putting in as much effort as I would to shout my words in order for them to come out as barely audible-whispers and cracking, broken speech. A friend, Lucas, even gave me the nickname “Squeak” by how often my voice cracked under these conditions.

I have just tried saying “My name is Ryan Bigg” and it comes out in a hoarse whisper. Just tried counting to 10 and I only was able to say 1, 5 and 7 correctly. As an extremely vocal person, this is going to suck bigtime.

So, as part-experiement and part-fucking-laryngitis(??) I’m going to go tomorrow without speaking any words. I will go about my usual routine of getting food + coffee for Chendo from the shops on the way to work, doing my job, getting lunch & dinner, having conversations with people, but all without speaking. I don’t want to exhaust myself by trying to speak. I am already exhausted today, even after 9 hours of some of the most beautiful sleep I’ve ever had.

For prep for this experiment I’ve already ordered dinner from Halim’s (Indian Restaurant) up the road using only pen + paper I bought. I wrote common words + phrases like “I am unable to speak due to Laryngitis. Sorry for the written prompts”, “Yes”, “No”, “Thank you”, “Lamb Rogan Josh”… etc.

This made me think of good-to-have iphone app. A common phrase book for those between us who cannot speak, either due to throat inflammation or those who are mute. You’d have the main screen which would be a 4 x 4 grid of common phrase words, kind of like the home screen, and you could tap them and bring them up on the screen and show it to the person. Then you could add your own as well. I think that would be really useful. What do you think?

Scoping by locales

November 8th, 2009 by Radar

Today in #rubyonrails, kiwinewt asked:

How can I have a model with a text field and have that text field in multiple languages?

To which he meant that he has a model and he wants different versions of text displayed based on whatever the locale is set to. This is quite the common question in the channel and previously I’ve drawn blanks, but today I had a Moment of Clarity +10 and coded up something amazingly simple.

It has two parts. The first is the code in the model:

class Page < ActiveRecord::Base
  def self.with_locale(&block)
    page = scoped_by_locale(I18n.locale.to_s) { block.call }.first
    page ||= scoped_by_locale(I18n.default_locale.to_s) { block.call }.first

    raise ActiveRecord::RecordNotFound, "The page you were looking for does not have a version in #{I18n.locale}" if page.nil?
    
    page
  end
end

And the second is how you use it:

  @page = Page.with_locale { Page.first }

Now if you set I18n.locale in your application and use with_locale it will automatically find records based on that locale.

Where did I put that puts?

November 4th, 2009 by Radar

This is the question I ask after I’ve just finished a massive debugging session and I run the tests and halfway through there’s something vague like “S3″ printed out. So I do a Cmd+Shift+F looking for that string and of course it doesn’t exist. What’s a guy to do?

Well, at Mocra we put this in our config/environment.rb file (although a better location would be in a required file located somewhere in lib, probably named debug.rb):

# Print the location of puts/p calls so you can find them later
def puts str
  super caller.first if caller.first.index("shoulda.rb") == -1
  super str
end

def p obj puts caller.first super obj end

And when we don’t want it we comment it out. This will give us the exact location of the puts so we can track it down and remove it.