bitfluent

Kamal Fariz Mahyuddin on Ruby, Rails, Git, Chef and other web development geekery.

I'm available for hire for Ruby and Rails development and training, and infrastructure automation with Chef worldwide.

Email me today.

You should follow me on twitter here.
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
Feb
18th
Mon
permalink

Github, tweaked plugins, and how it changes the dynamics of opensource contribution

As I use various plugins in my Rails apps, I find that I always need to make small tweaks to the plugin or the files it generates. This is why I like to use something like piston or braid to manage the plugins. It allows me to make any change at will and know that it will be part of the app when I deploy, but at the same time keep up with any new upstream changes.

The problem with this is that I can’t easily centralize my hacks so that my other apps can use them. I could host the plugin myself but I want to be tethered to upstream for the occasional update.

I found the solution in Github.

Just today, I cloned the restful_authentication plugin so that I can move out the model authentication concern into lib/authenticated_base.rb. This will leave your User model squeaky clean, like so:

class User < ActiveRecord::Base
  include AuthenticatedBase
end

You can now focus on adding new associations, validations and methods that are unique to your app without being distracted by all the authentication cruft. Credit goes to the caboo.se sample app for exposing me to this organizational technique.

So, what I have now is twofold:

  • a tweaked plugin that others can freely use in their projects
  • an opportunity for the changes to be merged upstream (Github notifies the original creator of the repo, if I’m not mistaken)

This marks a turning point for me in my opensource contribution. The barrier to entry for pushing patches is so low that I expect to see myself cloning a bunch more repos and making my teeny tiny fixes.

You can imagine a future where, for example, the Rails project is on git and that there would be many competing forks, each with their own flavor. Heavy contributors like Pratik Naik and the Russian Mafia could have Lifo Rails and Performance Monster Rails respectively. Suddenly, Rails is no longer just a web framework, it’s a web framework distribution.

Anyway, if you want to get clean:

$ git-submodule add git://github.com/kamal/restful-authentication.git vendor/plugins/restful_authentication

(I’m sure you can use braid, but I’ve never gotten it to work with a git repo)

UPDATE: Cristi Balan, the creator of braid, emailed to let me know mirroring a git repo with braid only works if you have a pretty recent git, above 1.5.4 or so.

Jan
31st
Thu
permalink
Fork me on GitHub