Posts from ...

Howto Expire ActiveRecordStore Sessions

Here's a little tid bit that most will already know, yet is somewhat elusive on a Google search: How to expire old sessions in Rails when you're using the CGI::Session::ActiveRecordStore session manager?

Doing so is as easy as setting up the following command to run in crontab using the rails provided script/runner:

/usr/bin/ruby /path/to/rails/proj/script/runner
  -e production
  "CGI::Session::ActiveRecordStore::Session.find(:all,
      :conditions => \"updated_at <
        (current_timestamp - interval '1 week')\"
   ).each do |session|
     session.destroy
   end"

The above code will find all session overs a week old and delete them. Rails' script/runner utility loads your whole environment for you, so you have access to all your models if you need to do more complex logic that what I've shown above. You can also string that whole command on the same line, I've just formatted it to make it easy to follow for you dense folks out there (of which I consider myself one). One other note, the above is for postgresql - I believe to do the same for mysql you will need to use this command:

/usr/bin/ruby /path/to/rails/proj/script/runner
  -e production
  "CGI::Session::ActiveRecordStore::Session.find(:all,
      :conditions => \"date_sub(curdate(), interval 7 day)
        > updated_at\"
   ).each do |session|
     session.destroy
   end"

ActiveRecord stumper - Magically magical fields

I seem to have gotten myself in a bit of a bind regarding this previously alluded to situation where my auto-timestamped fields weren't being updated with the latest time.

In an attempt to resolve the date inconsistency I renamed the "created_at" field to be "created_tm" so Rails wouldn't populate the date for me - and then I set the default value on the table column to be "NOW()". All right then, fire it back and to a test insert...

By the existence of this third paragragh it's pretty clear that didn't work. So here's my question:

Is there any reason why this ruby statement:

Relationship.new(:src_entity_id => 1,
                 :created_by => 1,
                 :target_entity_id => 485).save!
results in this SQL:
INSERT INTO relationships ("target_entity_id",
                           "created_by",
                           "created_tm",
                           "src_entity_id")
                   VALUES (908,
                           3,
                           '2005-12-13 20:22:28',
                           100)

If "created_tm" is not a magic column, nor is it's value explicitly set, why would Rails add its own value in?

I have no doubt this is occurring because of my own stupidity, I'm just counting on my public disclosure of said stupidity to compel somebody to help me out...
Also, Dirk pinged me to let me know he was having this same issue, although upon looking closer I don't know if it is in fact the same issue?

CDBaby Firefox search engine extension

Reading about CDBaby's impending conversion to Rails jogged my memory of something I've been meaning to do for awhile, make a CDBaby Firefox search extension. So, here it is:

My CDBaby Firefox search engine extension

Whenever I hear about new music I want to try I always do a search on CDBaby.com first, then go onto more commercial ways of acquiring the music if CDBaby doesn't have it. Hopefully this will make that process one step cleaner.

Let me know if you have comments, problems or feedback.

Making Typo properly ping Technorati (and others...)

With the trunk version of Typo you may or may not have noticed that your Technorati (or blo.gs etc...) pings aren't getting recognized. This is because Typo doesn't currently send the ping in the proper format. However, I just submitted this patch to the folks at typo that should remedy things.

When you add a new entry to your blog, most blogging software supports the weblogUpdates.ping ping specification that will notify blog aggregators and other services that your blog has been updated. This is done through a pretty simple SOAP call that just tells the service the blog that was updated and the root URL of the blog.

Typo seemed to support this functionality through its "settings -> General Settings -> URLs to ping automatically" section. However it was sending a POST request with a format that wasn't quite the weblogUpdates.ping format. (Not to mention that it wasn't a SOAP request). I noticed this and submitted this issue to the Typo guys. After sitting back and basking in my find for a day or two it dawned on me that I had every ability to fix the issue. So after toiling a bit and making a few passes, I did just that and submitted the above mentioned patch.

So why do I mention this? Because I'm egotistical and self-centered? Well, yes. But also because this announcement by scott made me a bit nervous that it might be awhile until the patch made it into the trunk and I thought a few people might want to get their posts recognized sooner by the very important ecosystem of blog aggregators and services. No knock on the Typo guys at all, just an opportunity to get the functionality in place sooner rather than later.

If you're not up to doing the whole patch application process yourself, you can download these three files into your current Typo installation. (Make sure you're on the most recent revision, though - 760 as of this writing)

app/models/ping.rb
app/controllers/application.rb
app/controllers/admin/content_controller.rb

Also let me know if you see a better way of doing things as I'm no Rails pro.

Creating weblogUpdates.ping SOAP web services with Rails

I've recently had the occasion to work on both the client and server ends of implementing the weblogUpdates.ping SOAP call and thought it might be worthwhile to post the results here.

First, a little background. "weblogUpdates.ping" is a way for blogging software to notify aggregators that there's been an update to the blog. If you use Technorati or blo.gs this is how your blogging package notifies the services when you post a new entry. The specification for this SOAP call is outlined here and here.

As you can see, it's a pretty simple call. We need to make a SOAP call to the "weblogUpdates.ping" method with two string arguments, the title of the blog and the absolute URL of the blog - not the permalink of the new entry. (taken from technorati docs)



  weblogUpdates.ping
  
    
      YOUR WEBLOG NAME HERE
    
    
      http://www.YOURWEBLOGURL.com/
    
  

So, on to implementing both sides of this in Ruby on Rails...

Let's start with the client side, if you have a Rails app (such as a Rails blogger like Typo) that needs to send out a ping to Technorati or any other blog aggregator then you'll need to send out this ping. This turns out to be quite simple, here's the jist of the code (derived from Why's example)

begin

  server = XMLRPC::Client.new2(URI.parse(endpoint_url).to_s)

  begin
    result = server.call("weblogUpdates.ping", blog_name,
                          blog_url)
  rescue XMLRPC::FaultException => e
    logger.error(e)
  end

rescue Exception => e
  logger.error(e)
end
Keep in mind this is a synchronous call - so if the aggregator is slow in responding it will hang your app. Some thought should be given to spawning the actual call in a new thread.

So what about when you're writing a Rails app that serves as an aggregator that needs to receive these ping calls? It's not as simple as sending the ping, but with Rails' strong web services support it's still quite easy. So here's how you go about doing that:

And there you have it, sending and receiving the SOAP weblogUpdates.ping call. You can now write your own Rails version of Technorati and Moveable Type, so have at it.

Ruby on Rails and Postgres, Love at first sight

With my recent selection of Planet Argon as my hosting provider for the rails app I've been working on I had two choices: use Postgresql or subject myself to ridicule and public humilition from the PA guys by sticking with MySQL. Fortunately I decided to take the opportunity to start learning about postgres, and I'm glad I have.

One of the unforeseen benefits I stumbled upon was using the inherits functionality of postgres to factor out some of the common columns that rails uses. For instance, everybody knows that adding the "lock_version", "created_at" and "updated_at" columns gives you free optimistic locking and auto-timestamping, respectively. This is great, but adding these columns to every table definition in your SQL scripts is somewhat tedious. Enter "inherits".

Instead of specifying these columns for every table like one would normally do:

create table users (
    id integer primary key default nextval('users_id_seq'),
    username varchar(255) not null unique,
    password varchar(255) not null,
    created_at timestamp not null default now(),
    updated_at timestamp not null default now(),
    lock_version integer not null default 0
);

create table documents (
    id integer primary key default nextval('documents_id_seq'),
    title varchar(255) not null unique,
    body text not null,
    created_at timestamp not null default now(),
    updated_at timestamp not null default now(),
    lock_version integer not null default 0
);
we can factor out the three common columns into their own table that the other tables can inherit from. For the purposes of this demo I've called this table "traceable":
create table traceable (
    created_at timestamp not null default now(),
    updated_at timestamp not null default now(),
    lock_version integer not null default 0
);

create table users (
    id integer primary key default nextval('users_id_seq'),
    username varchar(255) not null unique,
    password varchar(255) not null
) inherits(traceable);

create table documents (
    id integer primary key default nextval('documents_id_seq'),
    title varchar(255) not null unique,
    body text not null
) inherits(traceable);
Just as we can factor out common attributes of an object model into an abstract or super class, postgres allows us to do the same with our table model.

I like it when architectural layers synch up like this, and postgres makes it easy to do so. The only question I have is if this structure will lead to a performance hit that negates its convenience. I would imagine it is similar to using a view, although that is a largely uneducated guess.

And Planet Argon it is

It was pretty clear after my last post that there are some good options when it comes to Rails hosting (and there are some having a few issues - hopefully all temporary). So after checking it all out, I'm going to start out with Planet Argon, which makes me an argonaut, er planetonian, er planaliscious argoharrian? Anyway, if you can get past their very 1995-ish sign-up process (snail mail or fax the hosting agreement and no way to enter a credit card into a web form), it's all good. Great personal service and you can always find help on their IRC channel. Their startup documentation is still very much a work in progress (i.e. I can't find any) which forces you to be somewhat intelligent and figure stuff out on your own. But when Robby (the techie-owner) is always a stone's throw away on IRC, that's not an issue. Thanks to all those who commented on the original post, it turned out to be quite an active discussion.

If you sign up yourself and want to throw me a bone, put me down as your referrer. It will make me happy, which makes me happy.

Textdrive vs. Planet Argon

I've been waiting for the fictitious Rails App Hosting to get off the ground for awhile now and have come to the realization that, in the name of expediency, I may need to look at some other options. Gauging by the amount of chatter and the "I just think your website looks legit" factor it certainly seems that Textdrive is the big daddy in town while Planet Argon is the smaller but still quite active player in the Rails hosting space.

So the question becomes, does anybody have any strong opinions between the two services, or even more ideally, has anybody hosted on both and can give their overall opinion? My main priorities are ease of setup and configuration, tech support and scaleability...

RoR, Learning Ruby the Wrong Way

Like most people that have recently jumped on the Ruby on Rails bandwagon (or at least given it a try), one of the first things I did was read the Ruby on Rails book and jump into developing my own web app. Well, here I am a few months later looking at my initial version of the app - and I am completely disappointed. The code is crap - it's inelegant, somewhat procedural and completely un Ruby-like. And I blame it all on Ruby on Rails.

You see, in my rush to stay with the hype I've jumped into Ruby on Rails without spending due time learning Ruby. I suspect many people have done the same thing and what you will begin to see is a dilution of the talent in the Ruby community as more people come into the language the wrong way - through RoR.

It's not a bad thing that Ruby on Rails has brought exposure to Ruby, but it's obscuring the language itself which is unfortunate. In an attempt to rectify my mis-education I have taken a step back and am starting to explore the language before proceeding on with more RoR. Until developing with Ruby becomes intuitive to me I shouldn't be working w/ RoR. I mean how many people successfully learn Java by learning Struts first?

My hope is that I am amongst the minority, but I suspect there are others who have made the same mistake as I have.

Book Review: "The Ruby Way" by Hal Fulton

If you've ever bought a learning ruby book, there's a good chance it was the "pickaxe book" - Dave Thomas' "Programming Ruby: The Pragmatic Programmers' Guide". I've read it myself and it is as billed, an excellent book to learn Ruby from.

However, I'm actually finding that Hal Fulton's book, The Ruby Way is a better read for me. I'm coming from Java and while the Pragmatic book will set you on your way to learning the ruby syntax and some idioms, it doesn't do much more than that. I need to see how to use Ruby, concrete examples of common problems and how to solve them. I have no doubt that this need stems from my own ignorance and not on the lack of merit of the pragmatic book, but it has been my experience none-the-less. So, if you're pining for more Ruby lovin' after reading the pragmatic guide, give the Ruby Way a try, it may be the book that fills that void in your life.

Ruby On Rails caching, part 2

It's pretty obvious what phase I'm at with my app given my recent postings: that's right, figuring out an appropriate caching strategy.

It seems as though I've run across another nuance with caching - if you use the "caches_page" method in your controller for an action that is invoked via XMLHttpRequest (i.e. via AJAX), it won't get cached. For instance, building on my last issue:

class UsersController < ApplicationController

  caches_page :find, find_simple

  def find
    @user = User.find(params[:id)
  end

  def find_simple
    @user = User.find(params[:id])
    render(:action => 'find', :layout => false)    
  end

end

The "find_simple" method is the action that will be invoked via AJAX and, despite the caches_page directive, it does not get cached. A look at the logs reveals this, as does a look at the cache directory on your filesystem (there will be no users/find_simple/id.html).

The solution is pretty simple, use "caches_action" instead of "caches_page":

class UsersController < ApplicationController

  caches_page :find
  caches_action :find_simple

  def find
    @user = User.find(params[:id)
  end

  def find_simple
    @user = User.find(params[:id])
    render(:action => 'find', :layout => false)    
  end

end

The ramification of this switch is that now all your action filters will get executed for every request. However, as AJAX calls are usually pretty lightweight, action caching should be quite sufficient.

I know the "caches_page" method adds an 'after' filter to the controller for each of its actions - this issue seems to imply that the filter is bypassed when a request comes in via XMLHttpRequest. It would also imply that the app server/RoR knows the difference between a 'normal' request and an XMLHttpRequest one - which is not what I would have expected. Anyway, no skin off my back as the solution is quite reasonable.

Ruby on Rails/WEBrick - Using "caches_page" with a different base directory

I've come across a situation in my little sandbox ruby on rails app that might get some people. I'm trying to add caching to my controllers using the "caches_page" method, which will capture the complete output of the action being cached and store it as an html file in your filesystem. It's setup like so in your controller:

class UsersController < ApplicationController
  caches_page :find
  def find
    @user = User.find(params[:id)
  end
end

Without any monkeying around with the configs or the location of the cached output, it works great. I execute the controller the first time and see the SQL output in the debug log statements, and execute it again and see nothing (indicating it didn't even hit the controller and pulled the page straight from the cache). Perfect. I can even see the html output in "public/users/find/1.html.

However, I moved the location on my filesystem of the cached output to a different directory by adding this line to "config/environments/development.rb":

ActionController::Base.page_cache_directory = "/tmp/ror/cache"

Great, now when I hit the same page and then go look in the new cache directory I can see the same "users/find/1.html" file. However, upon closer inspection of my log files I see that it's never pulling and using the cached file for output - obviously defeating the purpose of such an endeavor.

To understand the problem we have to understand how the caching works. All the "caches_page" call does is take the raw HTML output from the full execution of the action (filters and action) and put it on the filesystem in a place where WEBrick is looking for static files. By default they're placed in the "public" directory, which is where WEBrick looks for static files first before handing off to RoR. Well, with my changed config that static place has moved, but WEBrick doesn't know about it - hence the cache not being hit on identical requests.

So it appears there are limited options. I've looked in the "scripts/server" file that bootstraps WEBrick and tells where WEBrick should serve files from, and it appears that you can only specify one such directory:

OPTIONS = {
  :port        => 3000,
  :ip          => "0.0.0.0",
  :environment => "development",
  :server_root => File.expand_path(File.dirname(__FILE__) + "/../public/"),
  :server_type => WEBrick::SimpleServer
}

So, adding another root to that path won't work (to have WEBrick serve from both "public" and the new cache directory "/tmp/ror/cache"). It would appear that our only viable options are to combine the cache and public directories into one physical location - either move the files in "public" to your cache directory or leave the config as it is out of the box and have your cached output sent to "public". This is the option I'm going with for now until I can figure out a better solution, although it's quite a pain to not commit the cache files into subversion after the cache has been used...