Develop Rails Like It's 1976 or Actually 1991 with Vim (or How Recovering TextMate Addicts Still Be Productive and More)

Posted by labrat

Decisions, decisions, decisions... I'm about to embark on another journey career-wise. I drank the kool-aid with extra strength since starting rails. It was the first time I've ever started programming and it was only natural that I'd buy a mac to go with the experience. I'm honestly glad I did and can't imagine using a Windows machine by choice even if it's just for the eye candy. It's also made me more familiar with UNIX than I ever would have aside from deployment crashing in flames. Unfortunately, not all job opportunities come with the chance to work with a mac and suddenly I was faced with not having my editor of choice: TextMate. For some reason I always felt limited on TextMate. There was just something about the navigation and editing that made things feel a bit clumsy for me. I have a really bad short-term memory and I usually like referencing several files while coding. I also felt like I needed more powerful navigation with files. Again, I just didn't feel natural with the key bindings. So, I finally switched to Vim or shall I say I'm still in the process. I've managed to find most of the stuff I found useful in TextMate like completion shortcuts and such. Of course, the fact that I decided to upgrade to Leopard only days before switching to Vim made my life a living hell this whole week but that's another story. Still, can TextMate do this: vim_rails.png

Japan's Largest User-generated Restaurant Review Service Rewritten in Rails

Posted by labrat

Tabelog.com, the Japanese user-generated restaurant review site, recently unveiled a renewed version of the site completely rewritten in Ruby on Rails. The site has roughly 3.8 million visitors per month (tripling visitors since last year) and roughly 29 million pageviews per month. Since first appearing on the scene in March 2005, Tabelog has attracted roughly 290,000 user-generated reviews coupled with a high-quality 5-star review algorithm that quickly attracted users.

The rewrite makes Tablelog the largest live Rails site in Japan. The development team decided on the rewrite after assessing the opportunity for reduced amount of code, a better separation of MVC, and faster development of market-driven features. The completely rewritten site successfully passed the transition test after going live over the weekend (10/19 to 10/22).

カカクコム、「食べログ」の開発環境にRuby全面採用--国内最大規模の事例に

月間380万人が利用するグルメのNo1クチコミサイト『食べログ.com』、Ruby on Railsを採用し、フルリニューアル - 株式会社カカクコム - CNET Japan

My First Rails App

Posted by labrat

I've finally released my first rails app to the world. It's yet another social networking + invitation site. I know people are getting tired of seeing these but when I originally thought it up, it was still a pretty novel idea. It just took me time to learn Rails on the side in getting there. It's really strange to release something to the public and actually use it. To be honest, it feels a bit draining to finally release it because you spent so much time in an endless cycle of coding and thinking. Yet after all the planning and thinking, you always come up against your limitations whatever they may be. It's given me a whole new level of respect for all the people who create useful and well-designed applications. They are truly heroes. I'm sick and tired of the endless internal feedback loop of working on it solo and in stealth so I'm hoping I can at least snag a handful of alpha testers that can give me feedback.

inbited.com

Monit for Your Uptime

Posted by labrat

One of the shocking things about going into production is to go on a little break or even get away from the house only to gasp in horror as you stare at a blank 404 where your earth shaking rails app should be when you get back online.

Integrating stuff like memcached into your rails app is mostly trivial thanks to the work of some wonderful rails hackers but keeping this moving parts moving is a task in itself. What’s the use of having a killer app that only works on your dev box right?

Naturally, the good thing about development is that everyone else has been there and done that. The other day I discovered monit thanks to igvita.com.

Sometimes a variety of bugs in plugins or your code can bring your web app down to its knees. This doesn’t even include those moments when your hosting service goes down for whatever reason whether it be maintenance or trouble. Smart developers (that’s you) will already have crucial parts of their service automatically restart along with any hardware restarting either by setting their chkconfig or whatever their system uses. Most of the libraries that we depend on are mostly reliable most of the time like the MySQL server that we only need to worry about start up initialization (although even this depends on how hard you push it).

Unfortunately, for most beginners, rails still continues to be a dream to develop in and a nightmare to deploy unless you know what you’re doing. Also random application crashes will increase the more moving parts you have such as memcached, mongrel, and acts_as_ferret.

Enter Monit

Monit is a wonderful little tool to ensure that your little web app keeps chugging along happily. It’ll monitor whatever you tell it to and ensure that they continue to run under the conditions you specify.

Using it with mongrel_cluster will ensure that users of your web app will be served a proper web page even as one of the other mongrels get culled for misbehaving.

In order to fully take advantage of mongrel_cluster and monit, you need to grab the mongrel_cluster prerelease. You can of course, use monit to serve as your cluster management but as Ezra notes, mongrel_cluster does a better job of keeping memory consumption in check as well as dealing with orphaned pids (only prerelease) that has given anyone that deploys rails a headache or two.

I can also vouch for the fact that monit has a slew of cool features to help you really keep the system humming along nicely. Remember memcached? Well, as much as it provides performace boosts to your app, it also introduces a potential headache. You see, when used in conjunction with mongrel you need to be careful to ensure that memcached is running before your mongrel starts. Otherwise you get weird behavior such as your flash[:notices] not showing up.

So, suppose your memcached crashes but mongrel stays up. Even if memcached got restarted, you’re only half way there since you need to restart mongrel immediately after that. Fortunately, this is trivial with monit because you can simply set a hierarchy by stipulating a depends on condition. This will ensure that whatever is being depended on will be restarted by monit first before the other processes get started.

  set daemon 60
  set init
  set mailserver localhost
  set mail-format { from: monit@monit.com }
  set alert who@gmail.com

  set httpd port 2812 and
      use address localhost
      allow localhost        

  check process mongrel_8000
     with pidfile /var/run/mongrel_cluster/mongrel.pid
     start program = "/usr/local/bin/mongrel_rails cluster::start -C /root/inbited.com/current/config/mongrel_cluster.yml --clean --only 8000" 
     stop program = "/usr/local/bin/mongrel_rails cluster::stop -C /root/current/config/mongrel_cluster.yml --clean --only 8000" 

     if totalmem is greater than 60.0 MB for 5 cycles then restart
     if cpu is greater than 50% for 2 cycles then alert                  
     if cpu is greater than 80% for 3 cycles then restart                
     if loadavg(5min) greater than 10 for 8 cycles then restart          
     if 3 restarts within 5 cycles then timeout
     depends on memcached                          

     if failed port 8000 protocol http                
         with timeout 10 seconds
         then restart
     group mongrel

  check process mongrel_8001
     with pidfile /var/run/mongrel_cluster/mongrel.pid
     start program = "/usr/local/bin/mongrel_rails cluster::start -C /root/inbited.com/current/config/mongrel_cluster.yml --clean --only 8001" 
     stop program = "/usr/local/bin/mongrel_rails cluster::stop -C /root/current/config/mongrel_cluster.yml --clean --only 8001" 

     if totalmem is greater than 60.0 MB for 5 cycles then restart       
     if cpu is greater than 50% for 2 cycles then alert                  
     if cpu is greater than 80% for 3 cycles then restart                
     if loadavg(5min) greater than 10 for 8 cycles then restart          
     if 3 restarts within 5 cycles then timeout  
     depends on memcached                               

     if failed port 8001 protocol http                
         with timeout 10 seconds
         then restart
     group mongrel

  check process mongrel_8002
     with pidfile /var/run/mongrel_cluster/mongrel.pid
     start program = "/usr/local/bin/mongrel_rails cluster::start -C /root/inbited.com/current/config/mongrel_cluster.yml --clean --only 8002" 
     stop program = "/usr/local/bin/mongrel_rails cluster::stop -C /root/current/config/mongrel_cluster.yml --clean --only 8002" 

     if totalmem is greater than 60.0 MB for 5 cycles then restart       
     if cpu is greater than 50% for 2 cycles then alert                  
     if cpu is greater than 80% for 3 cycles then restart                
     if loadavg(5min) greater than 10 for 8 cycles then restart          
     if 3 restarts within 5 cycles then timeout 
     depends on memcached                         

     if failed port 8002 protocol http              
         with timeout 10 seconds
         then restart
     group mongrel

  check process memcached
     with pidfile /tmp/memcached.pid
     start program = "/etc/init.d/memcached start" 
     stop program =  "/etc/init.d/memcached stop" 
     if failed host 127.0.0.1 port 11211 then restart

This sample config is based on igvita and Ezra’s. As you can see there’s a “depends on memcached” call. What this does is set a hierarchy so if memcached gets restarted, mongrels will get restarted afterwards. On initialization, memcached will get started first so your web app can function properly.

I plan on tweaking this so that I can be extra sure to have essential services like mysql and nginx humming along properly as well (although I’ve yet to see these go out, the load on my service is currently close to nil).

I’ve only touched on the tip of the iceberg really and I just think I might even check out how to use this to keep rogue apps from eating up too many resources on my mac.

Now, apps should never ever be crashing to start but things happen and rails will always have its kinks until well it’s… enterprise ready™. But hey, it’s more important that your app stays humming especially if you have moving parts like memcached or ferret that form an integral part of your service.

Monit will also dutifully email you of any incidences that trigger it. This combined with exception notification can provide you with valuable debugging info.

Monit makes Mongrel play nice! – igvita.com

Mongrel Mongrel Cluster 1.0.1.1 Prerelease: Healing power of the pack!

Rails Time Zone Guide for Beginners

Posted by labrat

Making your rails app aware of time zones can be a real pain. There's really nothing special about it. You simply want your app to display dates and time according to whatever time zone the end user happens to be in. The problem is that you have the server's time and the user's time and whatever values stored in the database for dates and time. This isn't supposed to be a detailed guide from beginning to end but a simple walk through to explain some things that tripped me up. Your mileage will vary. The first thing you need to do is follow all the steps in this excellent guide from Caboo.se. In my approach, I changed the set_timezone filter in application.rb to the following:

  private
  
  def set_timezone
    if logged_in? && !current_user.time_zone.nil?
      TzTime.zone = current_user.tz
    else
      TzTime.zone = TZInfo::Timezone.new(ENV['TZ'])
    end
    yield
    TzTime.reset!
  end
This takes advantage of the fact that I have this in environment.rb:
  config.active_record.default_timezone = :utc
  ENV['TZ'] = 'America/Los_Angeles'
You can of course, replace "ENV['TZ']" in the filter above with a valid time zone string such as 'America/Los_Angeles'. You always need to have a valid TZInfo::Timezone object when setting the time zone which is why we convert the string to a time zone object by calling TZInfo::Timezone.new("the_time_zone_string") otherwise you get funky errors like "TZInfo::Timezone constructed directly" and a mess of others. For my views I always format the date time into something more user friendly using strftime so I have this in one of my modules to convert the time in views.
  def tz_convert
    TzTime.zone.nil? ? self : TzTime.zone.utc_to_local(self.utc)
  end
  
  def full_date
    self.tz_convert.strftime("%m/%d/%Y %H:%M")
  end
  
  def short_date
    self.tz_convert.strftime("%m/%d %H:%M")
  end
The tz_convert method is written so it wont throw an error if the time zone isn't set. Like I said, this is an incomplete guide so you definitely want to read up on the other blogs out there:

caboose adding timezone to your rails app

Peter Marklund's Home : Rails Recipe: A Timezone Aware Datetime Picker

View Helpers Make Strings

Posted by labrat

One thing you might come up against trying to make your view templates more readable and concise is stringing together a bunch of tags generated by link_to or some other method. For example, I wanted to create nested comments with a thumbnail of the member profile, a link to the topic, and show the actual content. All the stuff generated by link_to and other helpers are ultimately spit out as strings. This will allow you to combine helpers by using the property of strings. Here are two ways to create the same output:
		def nested_comments(comments)
		  ul(comments) do |item|
		    member_thumb(User.find(item["user_id"])) +
		    link_to(item["title"], :controller  => 'communities', :action  => 'show_topic', :id  => item["id"]) +
		    "

" + item["content"] + "

" end end def nested_comments(comments) ul(comments) do |item| string = "" string << member_thumb(User.find(item["user_id"])) string << link_to(item["title"], :controller => 'communities', :action => 'show_topic', :id => item["id"]) string << "

" string << item["content"] string << "

" string end end
The bottom version is more readable in a larger sense but top is way more concise. They use one of the available ruby concatenation methods.

First Comes the Blog, Next Comes the Bug Tracker

Posted by labrat

It seems like even advanced rails developers go through phases. First they write blogging CMS apps:

typo

Mephisto—The best blogging system ever

SimpleLog. A simple (and free!) Ruby on Rails weblog application.

The simplest CMS you'll ever use @ Pagety

Then as they get even more advanced, they write bug tracking software:

We make bug tracking easy @ 16bugs.com

Porchlight - Bug tracker for small software development teams

Lighthouse

This isn't meant to be a critique or anything but I suppose it shows some kind of evolutionary path they take. Or maybe it's just a funny coincidence.

Has_many_polymorphs for Real Polymorphism

Posted by labrat

UPDATE: Evan has updated has_many_polypmorphs so that child and parent can access each other both ways. For the average user, this means just use it like you normally would.

One of the things about being a rails beginner is that you don’t know whether you can’t do something efficiently because you don’t know how to do it or because Rails just doesn’t support it.

I think polymorphic associations as they currently stand are pretty limited or at least you could say they impose limitations. Just read Josh Susser’s blog for various examples.

That’s how I ended up arriving on the has\_many\_polymorphs doorstep. If polymorphic associations are the flexible joints of associations has\_many\_polymorphs takes it to a new level with joints that can flex 360 degrees in every direction.

It was hard to find friendly documentation suitable for a beginner but it really is simply once you have it. My example is probably one of the most basic uses but it’ll have to do. Check the documentation on Evan Weaver’s blog or fish through the plugin directory for examples within the tests(it’s pretty well-documented).

In my application I have Pictures and I have a bunch of other models that will use pictures like Profiles or Communities. This is easy to understand. One way to do it is documented in the wiki How to Use Polymorphic Associations. This document is a bit old so I’m not sure if it’s still the most efficient way of doing it but you end up with two models solely for tying together two different models. You need a Folder model and Linkings model. Not only that you have to set up all the association statements correctly and specify callbacks and other stuff to make them useful.

With has\_many\_polymorphs you’ll get all this for free.

It’s really easy with examples so here we go:

class Picture < ActiveRecord::Base
  has_many_polymorphs :consumers, :from => [:profiles, :communities], :through  => :picture_consumers
class PictureConsumer < ActiveRecord::Base
  belongs_to :picture
  belongs_to :consumer, :polymorphic => true
class Community < ActiveRecord::Base

This is what the PictureConsumer scheme looks like:

create_table "picture_consumers", :force => true do |t|
  t.column "picture_id",    :integer
  t.column "consumer_id",   :integer
  t.column "consumer_type", :string
  t.column "created_at",    :datetime, :null => false
  t.column "updated_at",    :datetime, :null => false
end

As you can see, the Community class (and neither does the profile class) require any association to be declared. This is because has\_many\_polymorphs takes care of it for us. Really, it’s that simple. With those you can now do:

@some_community.pictures
or
@some_picture.communities

You can associate pictures with as many models that you would like. Has\_many\_polymorphs also allows you to create joins that are polymorphic on both sides. Less configuration and more flexibility is certainly a plus.

One big snag waiting for you is the above may not work as is (especially in the controller). You need a declaration in application.rb and your environment file for Rails to properly load the associations.

For me these include the below. For application.rb:

require 'app/models/picture'
class ApplicationController < ActionController::Base

(update: no longer needed since update, see link below or note at the very top)

In development.rb for my environment: config.after_initialize do config.has_many_polymorphs_cache_classes = true end

This ensures the associations get loaded properly even when used in the console under development or for rendering in views.

UPDATE: Don’t do this either. It may unload some model methods after the second request. If you don’t know what that means you’re safe not putting the above in your environment file. Everything works fine out of the box thanks to Evan’s hard work.

The entirety of the information here was ripped out of Evan’s blog so please check it out and send him your regards. It’s marvellous work that I’m surprised is not already part of Rails.

has_many_polymorphs activerecord plugin :: evan weaver

has_many :through: The other side of polymorphic :through associations

has_many :through: Many-to-many Dance-off!

dependency injection for rails models :: evan weaver

Back from the Abyss: A Helper to Create Nested Lists

Posted by labrat

Sorry for not writing in a while. I've been busy doing other stuff and on top of that DreamHost has been real brutal to this Mephisto blog. My blog was inaccessible for a long long time and there really wasn't anything I could do. Support requests simply came back as "can't do anything for third party software". Oh well, I'm not complaining but it's a shame. I'm using WordPress for another blog and I've got to say it's a pleasure to use a mature blog with lots of plugins to meet every need. I'm going to be tool agnostic from now on. That's not to say I want to do PHP. Mephisto is great for seeing a top class rails coder in action.

So anyways, as lot as DreamHost lets me run this blog, I'll try to write something up.

Today, I came across a great snippet you can add in your helpers to iterate over html lists, you know the typical ol ul elements.

Which lets you write: <%= ul @pages.map { |x| link_to_page(x) } %>

Well, this is a great time saver and way better than hand-coding it yourself but I wanted something that could produce a nested list from an array of arrays. Now my code isn't the most elegant but it works. It uses recursion to produce a nested list (although the spacing and newlines aren't included so the source looks garbled in real life).

So this in your views: <%= ol ["first", "first", ["third", ["second", "second", "second"], "third", "third", ["second", "second", "second"]]] %>

Becomes:

  1. first
  2. first
    1. third
      1. second
      2. second
      3. second
    2. third
    3. third
      1. second
      2. second
      3. second

Here's the snippet:

    def html_list(type, elements, options = {})
      items = elements.map  do |element|
        if element.is_a?(Array)
          element = html_list(type, element, options = {})
        else
          content_tag("li", element)
        end
      end
      content_tag(type, items, options)
    end

Haven't tried it for something nested deeper than two elements so mileage may vary. What can you use it for? I was thinking nested comments (will have to figure that one out).

vemod.net - List Helper for Rails

Mongrel 1.0.1 is Out

Posted by labrat

Nice that they are following conventions by releasing 1.0.1 like rails. Convention > configuration.

Alright folks, after nearly a month of pounding and beating up the Mongrel 1.0 RC1 release we’re putting out the official 1.0.1 release. It’s official, so let the chaos spread across the 2.0 web in a destructive blaze viewable from the buckle of Orion’s Belt. Or, you could just install it with: $ gem install mongrel

Mongrel: News

Rails 1.2: Maybe Dreamhost Will Give Me REST

Posted by labrat

Rails 1.2.1 is out now. This is great news. Now I don't have to develop on edge. Of course, the only thing on edge was really me but hey, now I'll just develop against 1.2.1 instead of second guessing everything else. In other news, one reason of my recent silence is the fact that my mephisto-powered blog has been down a bit. Seems like we get no love from DreamHost since we're hogging resources. Couldn't figure out the problem, didn't bother. Of course, I didn't do anything and am now online. Don't want to migrate it to Rimuhosting and use precious resources for my toy app. What shall I do? Been using WordPress for another blog I started. Works nice. I'm sure Mephisto will get there soon. I wonder how long it'll take Dream Host to bite the 1.2.1 bullet after the last upgrade screwed all the Typo blogs they had? Hmmm....

Riding Rails: Rails 1.2: REST admiration, HTTP lovefest, and UTF-8 celebrations

Code Fast

Posted by labrat

I've lately been falling into the trap of thinking about implementation more than coding. All the more crippling since I don't even have a barely functional demo. It reminds me of a favorite phrase coined by a Japanese mogul who played a key role in reconstruction negotiations during Japan's occupation, Shirasu Jiro. An iron rule of conduct he enforced at his country club golf course was "play fast". It was how he lived his life as well, right until the very end. I think it applies to code as well. The less time you spend implementing the more you forget and have to backtrack or break stuff inadvertently. It's not an excuse for sloppy code either. If you want to code fast, in other words get something done, you can't be going back and forth. Just like golf, taking random shots at the ball will keep you wandering the course for lost balls. Not only will you be holding back the people behind you, you'll also pose a safety hazard. All the best coders do in fact code fast and their code is quality too (though there are exceptions). You simply can't produce a ton of sloppy code without everything come crashing down in flames.

Apple takes over DIGG!!

Posted by labrat

This is way too hilarious! Mad props to the dude with an aquarium story that's holding its own. apple_digg.png

A Beginner's Tutorial Starring DHH

Posted by labrat

Whoa! Don't how this guy scored a one-on-one tutoring session with the one and only DHH but I'm sure glad I found this. There's really nothing new here that you wouldn't find in the original screencasts other than DHH fumbling with the scaffold and looking up the rails API!!! I'm not trying to make fun or put down DHH but seeing that is such a sigh of relief for people like me doing much more fumbling. It's okay. For all the hype and some of the negative press he gets you can't deny the fact that DHH is very generous for doing this and an all around nice guy. It's also true for some serious rails hackers like Rick. These people are constantly giving people like me the gift of their time by providing their talents to open source projects. That's definitely one of the things I love about the rails community.

CoderPath via Rails Christmas gift

5 OS X Apps that You Didn't Know You Needed

Posted by labrat

I think a lot of people are unaware of just how many pieces of great software for the mac are out there. It seems like every three days I'll read about how people are switching to the mac in record numbers. A wider user base means that much more opportunities for software developers to make money. However, what a lot of people don't realize is that there are also many developers switching to the OS X platform as well. With that in mind, I've taken care to compile a list of "hidden gems" that can make a real quality difference to your mac experience on a daily basis. There are no earth-shattering apps or obvious choices like Quicksilver but apps that will make a little difference every day, whether it's a small performance gain or fulfilling a useful function that many people aren't aware of. Most of these apps are shareware but offer decent trial periods.

Main Menu: Free

The mac is relatively maintenance-free compared to Windows. However, after a while it does help to do a little maintenance and get rid of that accumulated junk that slowly drags you down. Before I found Main Menu, I used to use Onyx which has similar functionality. The big difference is Main Menu stays accessible to you from the menu bar. Quick and simple.

"Rebuilding your Spotlight library for faster searching, repairing permissions, cleaning caches to improve application performance, and even more advanced settings — such as enabling and disabling the Dashboard — are no more than two clicks away."

Main Menu

WriteRoom: $24.95 (free version available)

Ever sit down to write something only to find yourself distracted by emails, chats, new RSS feeds coming in, or some app in your dock begging for your attention? The sad fact is we're not as good at multi-tasking as our computers are. Sure, we can eat a bag of chips, drink soda, and watch TV at the same time but some things require concentration, especially if you want a decent amount of quality and get the task done on time. Writing is one of those activities. WriteRoom will turn your mac into a classic typewriter and I mean it in a good way. This app will give you one big blank screen with no dock, no menu bar, no scroll bars. Just text. Check this screen out for an idea of what you get. If you care about your prose, this will be a good investment. A free version (limited features and polish) is also available.

WriteRoom | Hog Bay Software

1Passwd: $29.95

Nowadays all browsers more or less come with password management built-in. Firefox does a nice enough job but did you know that if someone can access your Firefox profile folder, they can easily transfer you passwords and decrypt them? There's also no sane way to transfer these passwords since mac uses keychain for all password management and keychain integration for Firefox is still down the road. 1Passwd allows you to securely store and manage a single collection of password from any major browser. It can also import passwords from Firefox as well. It comes with many security options (like generating strong passwords) and can be synced across multiple macs. As an added bonus, their toolbar gives you a form filler so you can stop typing things like name, email, homepage, etc. when online shopping or commenting on a blog that you're visiting for the first time. It may seem a bit expensive but if you spend time participating in a variety of community-related sites or blog, this app will make a big difference.

Password Manager + AutoFill for Mac OS X

Xslimmer: $9.95

Most of the mac users I know personally have finally taken the plunge into the Intel world. The performance gains are really fantastic. Luckily, PPC users are not left behind as many apps migrate to the Intel platform with Universal Binaries or single installations that work on both platforms. However, did you know that Universal Binaries take up more space and usually run slower than a binary specifically suited for your chipset? Xslimmer will strip out the unneeded chunks of many apps and not only free up space but speed up formerly universal apps. I put Firefox on a diet but I hear it even works for the Adobe Photoshop Beta as well.

Xslimmer - Your Mac, on a Diet!

Hazel: $16

If you're like me or many others, your desktop or hard-drive is probably a mess with files strewn everywhere. I try to keep my desktop clean but that usually means dumping them in my documents folder. Who needs to organize when you have Spotlight right? Not exactly. The OS X has a bunch of functionality to keep your folders organized such as Folder Actions and Automator tasks but these require a bit of learning and is definitely not for an average user. Hazel lets you keep your folders tidy with Mail-like rules for keeping your folders neat. It can even apply rules retroactively.

Noodlesoft

None of these apps will take center stage on your mac with the exception of WriteRoom (if you write a lot). At most they run in the background or support a more major activity (like browsing) but these are nonetheless quality apps that can make a big difference to your experience over the long-term. Enjoy!