bitfluent

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

Reach me by email.

Aug
9th
Sat
permalink

Tumblr Client On The iPhone

Would having a tumblr client on my iPhone see me posting more frequently? Obligatory test post.

Posted with LifeCast
Jun
2nd
Mon
permalink

On the Beauty of Rubinius' Design (I Wish I Had Rails.new)

In Rubinius, you can spawn off a brand new complete VM by simply calling Rubinius.new. It’ll behave exactly as though it was invoked directly from an rbx binary sitting in your $PATH, complete with STDIN/STDOUT (which you can override). I believe this is one of the basis of how Rubinius’ multi-VM architecture works.

Anyway, I bring this up because I really, really wish Rails was architected in a similar fashion. I am building a CMS on top of Rails and would love to get my hands on a Rails.new if there ever was one. Here’s why.

In a CMS setting, very little of what Rails offers out of the box is usable. You don’t have access to Rails routes so from the very beginning, you don’t have Rails automatically invoking the right controller, the right action and rendering the right view. This doesn’t make sense anyway - you don’t expect your CMS users to start writing controller code in your web editor, do you? (Unless you are Heroku.)

On a slight tangent, the assumption when writing a CMS is that when you ship, you would have written every conceivable controller and model there is (views don’t fall into this because users are generally familiar with the concept of customizable templates). One strategy to extend your “frozen code base” is via the use of widgets and third-party apps (like Facebook) so that you can create seemingly new pages served by custom controllers.

So how do you design a CMS? I’ve been prototyping something for the past week and came up for a breather to check out how other people have solved it. I am delightfully surprised to find out that Radiant does it very close to what I have. In particular, Radiant has one single controller that accepts all requests (lets ignore the entire admin portion for the time being). Based on the path array (provided by the globbed route), it decides what to do / where to dispatch. It takes care of locating the page that corresponds to the URL (it uses a Page model), rendering it and returning the result to the user. It is interesting to note that Radiant directly manipulates the request and response objects, something that Rails developers almost never had to reach for in a regular app. On the other hand, I am exploring the use of serializing the templates to disk and simply calling render :template on it.

Wait a minute. Holy cow, we just built (a simplified) Rails on top of Rails!

What I’d love to see here instead is a Rails.new method just like Rubinius. Boom, a full blown MVC at your fingertips. Configure it right and there you have your very own CMS with minimal work. Or maybe there is. Lazyweb?

May
2nd
Fri
permalink

An update in a really long while

Woah, one month with no updates.

I started contracting for a startup in Seattle, WA since beginning of April and have been neglecting to update stuff. It’s pretty nice here plus I get to access things that people here take for granted like attending Seattle.rb hack nights, Pandora, Hulu and this weekend, Barcamp Portland!

See you guys in a bit.

Apr
1st
Tue
permalink
Mar
30th
Sun
permalink

Updating Counter Cache in Migrations

I’m nearly complete with an app I’ve been working on, so I thought I’d dedicate some time for optimization. One of the first things I did to my models was to add counter caches so that performing counts on my association were fast.

First try,

class AddCommentCounterCacheOnTopics < ActiveRecord::Migration
  def self.up
    add_column :topics, :comments_count, :integer, :default => 0
  end

  def self.down
    remove_column :topics, :comments_count
  end
end

Very standard. However, it initializes the column to 0, effectively “losing” all my comments (they’re there in the DB, but Rails adds an additional optimization whereby it won’t fetch the association if the counter cache is 0). Looks like I need to update the comments_count column to whatever it was at the time of migration.

Second try,

class AddCommentCounterCacheOnTopics < ActiveRecord::Migration
  def self.up
    add_column :topics, :comments_count, :integer, :default => 0

    Topic.find(:all).each do |t|
      t.comments_count = t.comments.count
      t.save!
    end
  end

  def self.down
    remove_column :topics, :comments_count
  end
end

Two things to note: First, I’m using the #count method in t.comments.count because calling #size will use the value in t.comment_count which is 0. #count on the other hand will perform a SQL count(). Second, this won’t work! Why? Because counter cache columns are set to attr_readonly.

To work around this, a little hack. Final result,

class AddCommentCounterCacheOnTopics < ActiveRecord::Migration
  def self.up
    add_column :topics, :comments_count, :integer, :default => 0

    def Topic.readonly_attributes; nil end # A little evil hack

    Topic.find(:all).each do |t|
      t.comments_count = t.comments.count
      t.save!
    end
  end

  def self.down
    remove_column :topics, :comments_count
  end
end
Mar
24th
Mon
permalink
Excellent panel on scaling customer support. Definitely something to take into account whenever you think of launching a new product out there. Are you too caught up in the idea and the development, forgetting the most important ingredient of your success: the users?
Mar
20th
Thu
permalink

My First Podcast Mention!

It’s the first time I’ve ever gotten mentioned in a podcast! It’s on Episode 023 of the Rails Envy Podcast for my blog post on using the Fire Eagle gem with Rails.

Download the episode and fast forward to 11:24 :)

Mar
18th
Tue
permalink

Google Gears for Safari Soon?

Adds support for offline storage for Web applications in SQL databases link ยป
- from About the Safari 3.1 Update via sharedcopy.com

permalink
Jaws drop How it recovered from the guy kicking it and later slipping on ice was freaking amazing! via SvN
Mar
17th
Mon
permalink

#ruby-lang

  • ddfreyne: Somebody decided that the best way to let all tests pass... is to comment out the tests that fail
  • ddfreyne: ...
  • kamal_fariz: i'd go one further and mock rspec's expectation matcher to return true
  • ddfreyne: heh