bitfluent

Kamal Fariz Mahyuddin on Ruby, Rails, Apple and being a Dad.

Reach me by email.

Mar
11th
Tue
permalink

Interfacing a Rails App to Fire Eagle Pt 1: Exploration via IRB

Here are my notes as I explore interfacing a Rails app to Fire Eagle. Tokens have been masked to protect the innocent :)

  1. Create a new application.
  2. Get the fireeagle gem.

    MacBook-Pro:src kamal$ git clone git://github.com/kamal/fireeagle.git fireeagle
    Initialized empty Git repository in /Users/kamal/src/fireeagle/.git/
    remote: Generating pack...
    remote: Done counting 377 objects.
    remote: Deltifying 377 objects...
    remote:  100% (377/377) done
    remote: Total 377 (delta 192), reused 0 (delta 0)
    Receiving objects: 100% (377/377), 75.91 KiB | 9 KiB/s, done.
    Resolving deltas: 100% (192/192), done.
    MacBook-Pro:src kamal$ cd fireeagle
    MacBook-Pro:fireeagle(master) kamal$ rake install_gem
    (in /Users/kamal/src/fireeagle)
    sudo gem install --local pkg/*.gem
    Successfully installed fireeagle-0.6.1
    1 gem installed
    Installing ri documentation for fireeagle-0.6.1...
    Installing RDoc documentation for fireeagle-0.6.1...
    
  3. Fire up irb and instantiate a client with the Consumer Key and Secret provided by Step 1.

    MacBook-Pro:~ kamal$ irb
    >> require 'fireeagle'
    => true
    >> client = FireEagle::Client.new(
      :consumer_key    => 'AAAAAAAAAAAA',
      :consumer_secret => 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB')
    => #<FireEagle::Client:0x1bef504 ...>
    
  4. Generate a Request Token and associate it with the user because we’ll need to locate who authenticated our app.

    >> client.get_request_token
    => #<OAuth::Token:0x1bddb24 @secret="emfPurZAbYlRqNL7fSxhXOkxCJRZ2T1r", @token="mGxmGcGPNyjr">
    >> current_user.update_attributes!(
      :request_token        => client.request_token.token,
      :request_token_secret => client.request_token.secret)
    
  5. Redirect the user to the Authorization URL.

    >> client.authorization_url
    => "https://fireeagle.yahoo.net/oauth/authorize?oauth_token=mGxmGcGPNyjr"
    
  6. After the user grants us permission, Fire Eagle will redirect the user’s browser to our Callback URL (defined in Step 1) with the same oauth_token params.

    http://yourapp.example.com/your_call_back_path?oauth_token=mGxmGcGPNyjr
    
  7. Find the User by the oauth_token and instantiate a new client (client2 in our IRB session) with the request token and secret.

    >> user = User.find_by_request_token(params[:oauth_token])
    >> client2 = FireEagle::Client.new(
      :consumer_key         => 'AAAAAAAAAAAA',
      :consumer_secret      => 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB',
      :request_token        => user.request_token,
      :request_token_secret => user.request_token_secret)
    
  8. Convert the Request Token to a long-lived Access Token and save it. Optionally, you can nil out the Request Token because you are not going to need them anymore.

    >> client2.convert_to_access_token
    => #<OAuth::Token:0x23c4824 @token="CCCCCCCCCCCC", @secret="DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD">
    >> user.update_attributes!(
      :access_token         => client2.access_token.token,
      :access_token_secret  => client2.access_token.secret
      :request_token        => nil
      :request_token_secret => nil)
    
  9. Go to town! From here on out, you can directly instantiate a client using the user’s Access Token to read or update their location.

    >> client3 = FireEagle::Client.new(
      :consumer_key        => 'AAAAAAAAAAAA',
      :consumer_secret     => 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB',
      :access_token        => user.access_token,
      :access_token_secret => user.access_token_secret)
    >> client3.update(:q => 'petaling jaya')
    => #<FireEagle::Response:0x2549a8c ...>
    >> client.user.best_guess.name
    => "Petaling Jaya, Malaysia"
    

A lot of the stuff above can be extracted into a Rails plugin. First dibs on acts_as_hatchling!

permalink
Flying is simply hours of boredom punctuated by moments of stark terror
916 Starfighter - Amazingly detailed recollection of a test flight gone bad
Mar
8th
Sat
permalink

On Providing Alternate Labels to ActiveRecord Attributes

I cooked up a simple enhancement to ActiveRecord::Errors#full_messages to allow me to pass a mapping of attribute to label. Here’s the snippet:

module ActiveRecord
  class Errors
    def full_messages_with_attr_mapping(mappings)
      mappings.symbolize_keys!
      full_messages = []

      @errors.each_key do |attr|
        @errors[attr].each do |msg|
          next if msg.nil?

          if attr == "base"
            full_messages << msg
          else
            full_messages << (mappings[attr.to_sym] || @base.class.human_attribute_name(attr)) + " " + msg
          end
        end
      end
      full_messages
    end
  end
end

Pastie Link

Let me walk through the scenario where I found this snippet useful.

Suppose I had a User model with the field ic to store the Malaysian National Registration Identification Card number. If I hit validation errors, I’ll get an ugly error message when I use @user.errors.full_messages.each { ... }

Ic is not valid.

With the snippet above, I’ll call it with @user.errors.full_messages_with_attr_mapping(:ic => 'I/C Number').each { ... } and get

I/C Number is not valid.

Much nicer.

However, I don’t like this solution much because I can’t alias_method_chain this to full_messages (because of the explicit mapping params). The downside of this is @user.errors.each_full { ... } will not do what I want as it uses full_messages.

Ideally, I want something that looks like:

class User < ActiveRecord::Base
  attr_label :ic => 'I/C Number', :hp => 'H/P Number'
  validates_mykad_of :ic
  ...
end

or, we can add a new key to specify the preferred label, much like how validates_* lets you override the error message.

class User < ActiveRecord::Base
  validates_mykad_of :ic, :message => 'is not valid', :label => 'I/C Number'
  ...
end

Or something like that.

I prefer Option 1 as it opens up more than just validation error messages. Other places it’ll be useful is in forms

<% form_for :user do |f| %>
  <%= f.label :ic %>
<% end %>

Is there a better way? Are there plugins that allow one to do this already?

Mar
7th
Fri
permalink
Mar
5th
Wed
permalink

Git Utilities You Can't Live Without

I found some new git toys to add to my toolbox. Let me share them with you:

1. git-completion.bash

The git tarball contains a sweet bash completion routine for git. Stick a copy from git-1.5.4.3/contrib/completion/git-completion.bash to /opt/local/etc/bash_completion.d/git-completion and tab away!

DEMO

MacBook-Pro:webrat kamal$ git <tab><tab>
add                 cherry              diff                instaweb            rebase              show-ref
am                  cherry-pick         fast-export         log                 relink              st
annotate            ci                  fetch               lost-found          remote              stash
apply               citool              filter-branch       ls-files            repack              status
archive             clean               format-patch        ls-remote           request-pull        submodule
bisect              clone               fsck                ls-tree             reset               svnimport
blame               co                  gc                  merge               revert              tag
br                  commit              get-tar-commit-id   mergetool           rm                  up
branch              config              grep                mv                  send-email          var
bundle              convert-objects     gui                 name-rev            shortlog            verify-pack
checkout            count-objects       imap-send           pull                show                whatchanged
checkout-index      describe            init                push                show-branch
MacBook-Pro:webrat kamal$ git br<tab>
br       branch
MacBook-Pro:webrat kamal$ git branch <tab><tab>
HEAD            master          onchange        origin/HEAD     origin/master

Pastie link if you can’t see it in full.

I like that last bit the most. It found my available branches. It can do a whole lot more. From the inline README:

- local and remote branch names
- local and remote tag names
- .git/remotes file names
- git 'subcommands'
- tree paths within 'ref:path/to/file' expressions
- common --long-options

2. Git-aware PS1

Once you have the git-completion file, you can set your PS1 to display the current branch you are in.

For stock-looking Leopard PS1, stick this in your ~/.bash_profile

PS1='\h:\W$(__git_ps1 "(%s)") \u\$ '

DEMO

MacBook-Pro:src kamal$ cd webrat/
MacBook-Pro:webrat(master) kamal$ git co onchange
Switched to branch "onchange"
MacBook-Pro:webrat(onchange) kamal$

It’ll only display the branch if it senses you are in a git repo. Freaking sweet or what??

3. git.rake

I stole this Rake task from the Rubinius project. Stick it in your lib/tasks directory. Rake now has new git powers.

MacBook-Pro:webrat(master) kamal$ rake -T git
(in /Users/kamal/src/webrat)
rake git:push    # Push all changes to the repository
rake git:status  # Show the current status of the checkout
rake git:topic   # Create a new topic branch
rake git:update  # Pull new commits from the repository

Now everytime you want to work on something, create a git topic branch by issuing rake git:topic.

MacBook-Pro:webrat(master) kamal$ rake git:topic
(in /Users/kamal/src/webrat)
Topic name (default quick): feature_x
git checkout -b feature_x
Switched to a new branch "feature_x"
MacBook-Pro:webrat(feature_x) kamal$

Edit, edit, edit. Commit. Time to push upstream with rake git:push.

MacBook-Pro:webrat(feature_x) kamal$ rake git:push
(in /Users/kamal/src/webrat)
Switched to branch "master"
* Switching back to master...
* Pulling in new commits...
git fetch
git rebase origin
Current branch master is up to date.
* Porting changes into feature_x...
Switched to branch "feature_x"
git rebase master
Current branch feature_x is up to date.
* Merging topic 'feature_x' back into master...
Switched to branch "master"
git merge feature_x
Updating e25c574..0eb83d5
Fast forward
 doc/README_FOR_APP |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
* Pushing changes...
git push
Counting objects: 7, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 414 bytes, done.
Total 4 (delta 1), reused 0 (delta 0)
refs/heads/master: e25c57 -> 0eb83d
To git@github.com:kamal/webrat.git
   e25c574..0eb83d5  master -> master
* Switching back to feature_x...
Switched to branch "feature_x"
MacBook-Pro:webrat(feature_x) kamal$

Dude, seriously. All that switching around, fetching, rebasing, merging? I bet only Linus Torvalds remembers the whole sequence off the top of his head.

Hope you enjoyed that. Also, I’ve got 5 GitHub invites if anyone wants ‘em.

Feb
28th
Thu
permalink
Feb
26th
Tue
permalink
Resurrecting MissingDrawer plugin for TextMate Cool to see the TextMate plugin I&#8217;ve been using has been updated.
Resurrecting MissingDrawer plugin for TextMate Cool to see the TextMate plugin I’ve been using has been updated.
Feb
21st
Thu
permalink
I think Ruby is pretty particularly cool. But no, not really - we’re not doing rocket science, we’re just trying to get people laid.
Feb
19th
Tue
permalink

Malaysia.rb February 2008 Meetup

Ruby Implementation Night is the theme of the Malaysia.rb February 2008 Meetup. There will be talks on Rubinius, JRuby, Ruby 1.9 and smatterings of other stuff.

Also, FREE PeepCode T-Shirts and Episode Coupons giveaway!

When:

Thursday, February 21st 2008, 7:30PM

Agenda:

7:30 - 8:00pm   Socializing
8:00 - 8:15pm   Opening by the Organizer
8:15 - 8:45pm   "Getting Started with Rubinius" - Kamal Fariz
8:45 - 9:15pm   Open Lightning Talks (geared towards JRuby, Ruby 1.9 or whatever you fancy) - Volunteers??
9:15 - 9:30pm   PeepCode T-Shirt and Episode Coupon Lucky Draw and Close

Cost:

Free. No registration required, just come right in, buy a drink, have a seat, and join the crowd. Invite your friends.

Contact:

kamal.fariz@gmail.com
+60123099143

Where:

Near UNITAR Kelana Jaya
Location

Directions:

  1. Go to new Giant Supermarket, Kelana Jaya
  2. Go to UNITAR, and then go to the lane behind it.
  3. Go to the Restoran Utara - we all meet there - venue is in adjacent shoplot.

UPDATE: Meetup location changed to Kelana Jaya. See directions.

permalink