permalink_fu has been great to create a Search Engine Optimized (SEO) friendly URL, but I was a bit irritated when the-permalink-is-getting-too-long-with-too-many-unecessary-keywords.

From some of the SEO tips I read, it is advisable not too put too many keywords in the URL. Unecessary stop words such as ‘the, a, in, on, and the list goes on’ can be removed, and the search engine robots will not be irritated too.

I wrote permalink_fu_hack plugin some time ago to solve this problem, thought some of you may find it useful in your application. To think about all the possible stop words, I took the shortcut, and got the inspiration from SEO Slugs Wordpress plugin by Andrei Mikrukov.

It is a monkey patch for permalink_fu, you need to first install the permalink_fu plugin. It also has an additonal :unique option to turn off the feature to automatically create unique permalink, which on some cases where the permalink already includes a unique primary key id, I find that the extra check is not necessary. With the :unique option, you can set it to false for such occasion.

Installation

  script/plugin install git://github.com/technoweenie/permalink_fu.git
  script/plugin install git://github.com/jugend/permalink_fu_hack.git

Example

  class Article < ActiveRecord::Base
    has_permalink :title, :filter_stop_words => true,
        :unique => false
  end

  article = Article.new
  article.title = 'The Permalink Is Getting Too Long With Too Many Unecessary Keywords'
  article.save
  puts article.permalink     # => 'permalink-getting-long-unecessary-keywords'

Additional has_permalink Options

  :unique               
     # Create unique permalink (default: true).
  :filter_stop_words 
     # Flag to filter to stop words (default: false)
  :stop_words         
     # Array of stop words to filter (default: auto assigned to stop words similar to SEO Slugs Wordpress Plugin).
  :max_words         
     # Maximum number of words to show on permalink (default: 6)

BookJetty in Digital Life

WED, 13 AUG 2008

BookJetty in Digital Life

BookJetty finally makes it to Digital Life, I’m humbled to read BookJetty mentioned as one of the high flying-tech from Singapore, considering it was started from a bare simple application started out of curiosity.

Hopefully with this article BookJetty will be able to reach out to more book lovers and library users in Singapore. Special thanks to Irene for the writeup.

Click here for the full article on Straits Times.

Remember how we used to browse books in the bookstores, and check out the innerside of the back-cover, which usually contain a short biography of an author. I find that knowing the author’s biography helps me to appreciate his/her book more, and helps me to decide if I should read or buy the book at the very first place.

There are hundreds of thousands of authors in BookJetty database at the moment, and it is definitely not possible to update all at once. If you are BookJetty users, when you are free, do help out to update the author pages, and gracias for that. Below is the screenshot of how it looks like.

Author Page

You can choose to become fan of an author; author’s average rating and other statistics are also shown on the page. This will help you to find out how popular is an author.

Better Book Covers and Scrolling Effects

Book covers in the scroller now have some dimension to it, it now looks more like a real books instead of just cover sheets, and I’ve also sped up the scrolling effect. With chunky covers, slower scrolling effect is quite distracting for the eyes, and believe it or not, you may feel dizzy after awhile.

Bookshelf Scroller

Polaroid Style Pictures

Other notable enhancement, is the palaroid-like user pictures with username shown below. I find that picture by itself without the username is less interactive and harder to associate with.

That’s all for now, stay tuned for other interesting additions to BookJetty, and happy reading!

The New BookJetty Launched

SUN, 11 MAY 2008

The plan for the new BookJetty was to bring social elements and other book related applications to BookJetty, on top of the existing feature to check books availability in the libraries. The new BookJetty marks the shift from a pet project to an official product supported by Pluit Solutions.

It was a daunting task from the beginning, considering there were so many things to do with very limited resources. The bad news also the existing codebase did not look too good, it was a pet-project codebase, patches were applied without proper product plan, it was on Rails 1.x, there were no unit testings, and stylesheets were not very organised either. It meant basically lots of re-works.

After much persistence and lots of hard work, today I am grateful and glad to announce that the new BookJetty is finally up!

Login Page

For a quick tour of what’s new, here are some of the highlights:

Connect with Your Friends’ Bookshelves

You don’t have to physically be at your friend’s home to check out what they have in their bookshelves. BookJetty now has a news feed that updates you of the new additions to your friends’ bookshelf, new reviews, new discussions and other activites.

Dashboard

Discussion Boards

It would be nice to be able to create a discussion topics about the books you are currently reading or have read. And you can now create a discussion topic.

Recent Discussions

Import Books

The problem with cataloging your books is when you get started. If you are bookaholic, there may be just too many books to add. Fear not if you have maintained your book list some where. You can easily import them to BookJetty. The import feature is smart enough to detect ISBN-10 and ISBN-13 from source data, irregardless of the text format. You can query from a webpage, an uploaded file or copy and paste text with ISBNs.

Invitation

To help you to start building your network of friends the invite feature is handy to invite your friends from your Gmail, Hotmail and Yahoo Mail. It can also import from your Plaxo address book.

Inbox and Sent Messages

Now you do not have to depend on email notifications to communicate with BookJetty members, the thread-based inbox message helps to keep you in conversation with your friends.

Inbox

Notifications

Built-in notifications to keep you informed of the activities related to you, such as replies to your reviews, discussion posts, or comments on your profile page.

Smart Bookshelf

Inline “Add to shelf” link can be found anywhere when you browse for books. Mouse over for more options as to which shelf to add to. On top of inline-rating feature, now you can also edit your bookshelf date with a simple date picker.

Smart Bookshelf

User Wall Posts

Previously there is a shout box on your user profile page. I thought it was too small and restricted. Now a bigger commenting box is available on your profile page. You can also reply to your friend’s post in a thread to keep the conversation going.

Explore

Based on the statistical data from members’ activities, various explore categories have been created, which include most popular, top rated, top favorites, and most discussed. You can also browse the different periods of time, i.e. this week, this month, this year or all time.

Explore

RSS Feed

If you are an RSS junkie, you can follow your friend’s bookshelf through RSS feed.

Privacy Control

I understand that it is important for you to control who can see your data and bookshelf, there is now a finer control of who can see your data.

Time Zone Support

With time adjusted according to your time zone, you won’t be confused about when exactly a post has been made. The best part is you do not have to configure your time zone, as it is automatically calculated with the help of Javascript.

Unicode Support

BookJetty now supports UTF-8 encoding, no problem if you have to comment in Chinese, Japanese and other non-latin characters.

More Bookstores

With the Unicode support, more book stores have been added, i.e. Amazon France, German, and Japan. More will be introduced in the future, the next one will be Barnes and Nobles.

Third Party Advertising

I have also introduced third-party advertising from Google Adsense. The advertising revenue I hope will be able to help to reduce the increasing cost needed the develop and support BookJetty.

Overall the new BookJetty has a better and more consistent layout. And from now on, there will be more regular updates, as the base is now ready. Coming out soon is the group/community feature.

I hope that you like the new BookJetty. For screenshots quick tour, click here.

Some time ago I wrote an article about CSS PNG Fix for IE by Rogie King, from Komodo Media, which is a great fix. But whether you realized it or not, there are some issues with the script if you monitor it closely, and some observant people have also notified me about it.

The problem is it will make repeated background ‘none’ call to your server, which probably shown as page not found or server error message in your access log, though the transparency fix stilll works. And here are some possible scenarios that may trigger that problem:

  • <img> tag linking to other image types other than PNG, e.g. JPEG or GIF images. This can be quite problematic if you use css selector to automatically fix all * html img tags found, you may get a lot of redundant background ‘none’ calls to your server if there are many tags which link to GIF or JPEG images.
  • If you accidentally put 'png' class name from some your elements without stylesheet background image.

So I took closer look at the code, re-formatted so I knew what was going on. There two types of fixes, one for <img> tag, while the other for background images. And it seems background image fix are still called for some of the scenarios above, and calling this.runtimeStyle.backgroundImage="none" was triggering the “none” request to the server. And two fixes that I did:

  • If it is <img> tag and it does not link to a PNG image file, do not perform background image fix, instead just ignore it.
  • If it is a background image fix, and the background image is not a PNG file, ignore it as well.

Here are the updated codes:

* html img,
* html .png {
  azimuth: expression(
    this.pngSet?
      this.pngSet=true : 
        (this.nodeName == "IMG" ? 
          (this.src.toLowerCase().indexOf('.png')>-1 ? 
            (this.runtimeStyle.backgroundImage = "none", this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "', sizingMethod='image')",
                this.src = "/images/blank.gif") :
            '') :          
          (this.currentStyle.backgroundImage.toLowerCase().indexOf('.png')>-1) ?
            (this.origBg = (this.origBg) ? 
              this.origBg :             
              this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
              this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "', sizingMethod='crop')",
              this.runtimeStyle.backgroundImage = "none") :
            ''
        ), this.pngSet=true
  );
}

Since Prof. Schubert Foo mentioned about BookJetty in VALA conference, there have been quite a number of requests from BookJetty users and librarians to link up their libraries with BookJetty.

And BookJetty welcomes the 10 most recent libraries that BookJetty links up with:

Australia

Singapore

United States

So special thanks especially to Prof. Schubert Foo to create the awareness, and to people like Hazman Aziz, Anne Holmes, Elaine Hopper, John Ruddle, Caroline Ramsden, John Edstrom, Lianne Gee, Stuart Lutzenhiser, Neredowell, Jessica Goodman, and others I could have inadvertently missed, for their suggestions and help with the link-up.

There are a few libraries suggested by some users could not be linked up because their z39.50 gateway is not active. I’m really sorry for that, while there are a few others are pending their verifications on the availability of the gateway with their librarians.

I’ve also worked on a simple XML spec which libraries can implement to link up with BookJetty, but the spec I think still need improvement, and I’ve yet to find more time to do that. The idea is so that libraries that do not support z39.50 gateway, with their internal IT staff support, can help to build that simple XML interface. While on my side, I’ll need to create the adapter.

In all, I’m really glad to see people around the world are seeing the value of BookJetty, which was started off merely as my pet project and to solve my own problems. It has encouraged me a lot in my long and tiring journey for the last few months, relentlessly days and nights, to work on the new release of BookJetty.

I hope with the new release, BookJetty will help to make our life more fun as a reader, a book lover, and people who know that there are tonnes of knowledge and pleasures, hidden down there in piles of writings binded as books.

And it’s definitely gonna be more fun if you can link up with your friends and family bookshelves, on top of your reviews, libraries, and online bookstores, all put under one roof with simple and user friendly interface. That is what I hope to achieve for the next release.

And the good news, I’m almost done, so, stay tuned for the new BookJetty this April.

I Found Peace

MON, 25 FEB 2008

Sometimes I wished I could still be a kid.
When life was much simpler.
Closed my eyes, and I found peace.

VALAThe VALA Conference is the Australian forum where the use of technology in libraries is discussed. Held twice a year, this year’s conference is the 14th Biennial Conference, and it continues to draw participations from librarians worldwide.

The 2008 conference was just over, held from Feb 5-7, 2008, at Melbourne Convention Centre.

It featured keynote speakers, Prof. Schubert Foo (Nanyang Technological University, Singapore), Prof. Michael Geist (University of Ottawa, Canada), Prof. Peter Lor (University of Pretoria, South Africa), Andy Powell (Eduserv Foundation, UK), Stuart Weibel (OCLC Programs and Research, USA) and Luke Wroblewski (Yahoo! Inc & LukeW Interface Designs, USA)

Hazman Aziz, an ardent trainee librarian in Nanyang Technological University (NTU), who has initiated NTU library catalogue integration with BookJetty, was in the conference; he hinted that BookJetty was mentioned by Prof. Schubert Foo.

From his review of the conference, Prof. Schubert shared that library can play the role of an info-concierge, where individual info object is a self sustaining, self containing node unit, can be content or service, in any format. The connectivity can be attained in many ways and not necessarily in a single way such as a mesh (web) of information. This example can be illustrated on BookJetty.com, where libraries such as NTU, National University of Singapore (NUS) and National Library Board (NLB) have integrated the connectivity for user discovered contents.

References:

Testing flash.now in Rails

TUE, 22 JAN 2008

I know this is an old problem, but I was still not satisfied with the current way of testing flash.now messages. If you love writing test cases, I’m sure that you will bump into the problem of testing flash.now message in your controller.

We usually use flash.now to display a message for an immediately rendered page, meaning not redirected:

flash.now[:notice] = 'You gotta be kidding me!'

The :notice key-value pair will be cleared once the action has been performed, and when you perform your test, flash.now[:notice] will return null.

# flahs.now[:notice] returns nil
assert_equal 'You gotta be kidding me!', flash.now[:notice]

# or in rspec
flash.now[:notice].should == 'You gotta be kidding me!'

So, what do we do now? The good news is Rails Wiki suggested two ways, which I’ll probably add the third way shortly after this:

First is to use assert_select:

assert_select "div.message", "You gotta be kidding me!"

The problem with assert_select, it needs to render your view, but often we just want to test the message without rendering the view, rendering view may throw errors especially if you are testing with mock objects.

The second way was suggested by Justin Gus, through his flashblack plugin, pretty nifty I thought, because it meets the objectives in which he stated:

  • The solution should only have effect in tests. It should not implicitly weave its way into production behavior.
  • I should be conscious when the behavior is in affect.
  • It should require very little effort on my part to enable the feature
  • It should be simple

Sample codes with flashback plugin:

flashback
get :index
assert_equal 'You gotta be kidding me!', flash.flashed[:notice]

But there’s one problem I was facing, I don’t like the call the extra flashback method.

So here is my attempt through a simple monkey patching of FlashNow and FlashHash class. The patch will store flash.now messages into flash[:now], which can be easily referred in your test codes, through flash.now_cache.

  1. Append this code snippet to your /test/test_helper.rb file or /spec/spec_helper.rb if you are using RSpec.
    module ActionController
      module Flash 
        class FlashNow
          def initialize(flash)
            @flash = flash
            @flash[:now_cache] = {}
          end
          
          def []=(k, v)
            @flash[k] = v
            @flash.discard(k)
            @flash[:now_cache][k] = v
            v
          end
        end
        
        class FlashHash
          def now_cache
            self[:now_cache] || {}
          end
        end
      end 
    end
    
  2. And now you can test flash.now mesages through:
    # Unit Test
    assert_equal 'You gotta be kidding me!', flash.now_cache[:notice]
    
    # RSpec
    flash.now_cache[:notice].should == 'You gotta be kidding me!'
    

Would welcome suggestion to improve this further. Thanks, and hope it will be helpful to you.

You know it’s funny that I read a similiar article for last year’s nominations forwarded by a friend. He told me to check out some of the young entrepreneurs in the region. I remember how I admired them, yet couldn’t stop to envy them for starting out at such a young age.

At that time, I had just started Pluit Solutions, and BookJetty was still a pet project; deep inside, there was a slightest hope to be shortlisted before I pass the age limit.

And believe it or not, yesterday’s morning, on BookJetty shoutbox, Isaak said, he spotted me in BusinessWeek.com, shorlisted as one of the 25 finalists for Asia’s Young Entrepreneurs.

I couldn’t be more happy than this, I was ecstatic, close to jumping up and down, not just for being featured, but at least for the re-assurance that the steps I took are leading me forward.

BusinessWeek's Asia Young Entrepreneurs

It has not been easy to start on your own, to run a business, to build a product, to bootstrap, to be frugal, to be wise, to take risks, to make mistakes, to learn, and to endure.

There are days when you wake up in the morning, feeling afraid that you may not have made it. Thus it is comforting to be acknowledged once in a while, and let it be the extra fuel for more late nights to burn. :)

BusinessWeek's Asia Young Entrepreneurs