Textmate favourite features

26 June, 2008

Sometimes you just forget the stuff you take for granted, but often you hear of people new to apps and not realising what's there. Here's a couple of the features of Textmate that are probably my most used... CMD + T - Go to file, pretty hot. List of files is shown in a dialog that it is in order of last edited/open file, with the last file you worked on as being selected. So I have a big habit of spending my life CMD+T then Enter all day along. Also by typing will filter down the list of files pretty damned fast. CMD + SHIFT + T - Go to symbol. Hotter still. This allows you to easily navigate through a file with ease. If you single click on a method name, it jumps to that method without closing the dialog box, double clicking closes the dialog. Particularly handy working on a large class/module this tends to stay open all day jumping back and forth between methods. CTRL + SHIFT + A - Hottest, subversion integration. Diffing from the commit dialog is a godsend. What's YOUR favourite feature of Textmate ?

Read More

Toronto Rails Night - Merb Presentation

11 June, 2008

Last night was yet another successful Toronto Ruby on Rails Nite put on by Corina Newby. The Toronto ruby community is rocking, evidenced by the large turnouts and fresh faces we see everytime. I'd guess 40-50 of Toronto's best and brightest Rails developers filled out the room. The unspace guys put on some much appreciated beer and made sure we're all informed about the upcoming RubyFringe (can't wait, I'm really hoping Zed's presentation is as exciting as his blog rants posts). Along with the other presenters of the night Mike and Libin/Wes/Carsten (up on TorontoRB.ca sometime in the next day or so). I did a presentation on Merb - The pocket rocket framework. Slides are are here (you may have to click through to the blog post to view if you're reading this in a reader/aggregator). Resource links are at the end of this post, and some discussion notes follow.. Presentation background Intended for people who are interested in looking at Merb, collating key points from blog posts, irc dicussions, mailing lists, and own experiences getting an app running with Merb (well the opposite way round, trying to get an app running and finding out those answers!). Hopefully the presentation collected a fair few hours worth of investigation into 20 or so minutes to help other people out Sports Bikes vs Sports Cars Useful analogy between Sports Bikes (Merb) and Sports Cars (Rails). Said cars have all the bells and whistles, everything is packaged up nicely, and it's pretty hard to hurt yourself, however given the nice packaging it's pretty hard to modify things. Sports bikes (Merb) on the other hand, are much more open to tuning, playing with, go faster, but need a bit more care Same same but different Rails and Merb apps are very much of the same likeness, but there are differences. Don't expect to be able to port code over 1:1 (especially if you've got a big reliance on plugins), and don't pepper the merb mailing lists/irc channel for "please make xyx behave like it is in rails merb-core & merb-more Two gems you need to get started (technically you only need merb-core). -Core is the stripped down bare minimum to get merb running. -more contains all the nice packaged goods to help you along the way merb-gen is your friend throw out script/* you're now doing everything in merb gen for generating your app, models, resources etc Key code differences refer to slides, but the code used is difference Agnostic in a very good way Merb is agnostic when it comes to ORM, test framework, js framework, rack adapator. merb-gen behaviour changes based on component used so if you're using rpsec, then stories get created vs unit tests. This is one of the reasons I'm very much into the idea of Merb Cool features part controllers, action args, router, covered off in the slides. Full apps, flat apps, very flat apps and thin servers and large grains of salt For performance stats (which are to be taken with a very large grain of salt). Hello world action on a single controller, rails would be about 300 req/s full merb app would be round 500 req/s flat merb app 500-550 req/s, a very flat app marginally quicker again, front a very flat app with thin (merb -I veryflatapp.rb -p 3000 -e production -a thin) and woah hold on, 1000 req/s ! Question was asked about benchmark figures and I made the point, they're going to be all over the place - it's easy enough to benchmark for yourself, that's the only thing that's really relevant. We know Merb is quick, just how quick will depend on your own application and uses. Merb, Rails and you The inevitable discussion at the end around, should you use Merb and how does it relate to Rails. Some of the goodness in Merb looks to be slowly being backported to Rails, so over time Rails will benefit from all of the wizardry going on in Merb (hopefully!). For those that like Merb's approach, and willing to forsake the vast library of rails plugins, and/or have very specific performance requirements and/or need to hack a framework around to do what they want. Merb looks to be killer. Ultimately it's upto you, so evaluate carefully. Resources Lots of link goodness..... http://merbivore.com http://wiki.merbivore.com http://merbunity.com http://merborials.com/ http://groups.google.com/group/merb http://github.com/search?q=merb http://mwrc2008.confreaks.com/ http://www.slideshare.net/search/slideshow?q=merb http://www.slideshare.net/search/slideshow?q=datamapper

Read More

CentOS 5 + Passenger

30 April, 2008

Tip of the day: For anyone out there with CentOS 5, despite what Passenger thinks, your http-devel libraries likely are installed. I was getting an error "you need to yum install http-devel" , which I had, but still getting the error. If like me, the export APXS2 as per passenger docs doesn't work, just add "/usr/local/apache/bin/" into your profile path and passenger will then work fine (I just checked by ensuring axps ran at the command prompt before running the passenger module install) In theory then you should be good to go...

Read More

Rails + PHP sharing the same session

10 April, 2008

Ya know there's times in your life you do things that feel 'wrong'. This somehow feels that way, but one of my buddies wanted to know how it's done, so here it is: I've got an application I maintain in PHP which has been in production for a good number of years. It's stable, works really well, however like any application I need to keep putting in enhancements, the pain curve of doing this is exponential with the time I've been using Rails, so over a couple of years you can imagine the pain is pretty high. Last week I thought to myself, enough is enough. I'm sick of writing PHP, I could do this so much faster in Rails. I've been churning away on a rewrite in the background, in Rails as and where I have time but I wanted a 'fix it now' kind of solution. So, why not have the same virtual host serve out both Rails & PHP, so long as the Rails app can find out if a user is currently logged in, then I can piece by piece enhance/replace the PHP app. Turns out it was pretty damned simple. Here's a quick guide assuming 1- Both apps are sharing the same database 2- In the session you're storing a user_id of the logged in user 3- App uses cookies So here we go...

1. Virtual Host Config

The first thing we need to do is get Rails to run under the same vhost as the PHP scripts are run. This is easy, just adding a ProxyPass directive into the Apache vhost for the site back to your mongrel(cluster), so lets say we had a REST resource "some_resource", you'd add in the ProxyPass line below

    ...
    DocumentRoot "/path/to/your/php/app/html"
    ProxyPass /some_resource http://127.0.0.1:3000/some_resource
    ...

Note that in production this would pass through to a balancer of course. The unintended consequence of this is that you also can share all of your assets served from your existing app without having to duplicate them in your Rails app.

2. Sessions - PHP

The next thing for this to work is we need to know for the Rails app that the PHP app has logged a user in - we need to share the sessions. There's not too much black magic here. When you start your session in the PHP app (well at least mine!) PHP was storing in a named cookie eg "myappname" a hash value via
session_name( 'myappname' );
. This hash value is used to look up the session tmp files stored on the server, inside those session files are the serialized objects that PHP stores in $_SESSION global. So you have three options. 1. The "read from file system and unserialize the session" route 2. Store the session in memcached and have both PHP/Rails connect to memcached 3. Use the db to store sessions and logged in user_id's, then load the user on each page load. Note there is a page on this on the rails wiki, devoted to approaches 1 & 2. However if you're not storing a tonne of variables in the $_SESSION then approach number 3 - the path of least resistance - will likely be just dandy for you... In my database I created a shared_sessions table - using a rails migration (detailed in step 3 below) This stored a unique key "session_hash", as well as other fairly understandable columns "user_id", "updated_at". As we're logging in and out from the PHP app, this will mostly maintain the sessions table. So I added a quick couple of functions Application_SetSession() and Application_ClearSession(). Application_SetSession() simply writes into the shared_sessions table the hash value from the cookie $_COOKIE['myappname'], the corresponding user_id, as well as the time of update, it looks something like this:
function Application_SetSharedSession($user_id)
{
    global $DB;
    $session_hash = $DB->real_escape_string($_COOKIE['myappname']);
    $qry = "REPLACE INTO shared_sessions SET `session_hash` = '{$session_hash}', 
                      `user_id` = '{$user_id}', `updated_at` = NOW()";
    if ( !$DB->query($qry) ) throw new DBException($qry);
}
ClearSession() clears out the appropriate shared_session record. As you can well imagine ClearSession() is called when the user logs out, SetSession() when they login as well as every page load. Your PHP app will now be setting/clearing the shared_session records as appropriate.

3. Sessions - Rails

  rails myphphack
  cd myphphack
  script/generate model SharedSession
  script/generate model User
  script/generate scaffold SomeResource name:string ... 
Right now you need to fill out the SharedSession model's migration, and delete the user model migration (it's already in the database!). In the SharedSession migration, make sure you're setting the unique index on session_hash, otherwise REPLACE INTO won't work. So, first we need to load the user on the Rails side. To do this we need look up the SharedSession model for the session hash, from the cookie that was set by PHP. It's available of course, doesn't care who set it we have access to it.
class ApplicationController < ActionController::Base
  before_filter :restore_user
  ...
  protected
  def restore_user
    unless @user = User.restore_from_php(cookies[:myappname])
      redirect_to '/login.php'
    end
  end
  ...
end
On the user model, we now need a method to find the user from the session_hash:
class User < ActiveRecord::Base
  has_many :shared_sessions
  def self.restore_from_php(session_hash)
    find(:first, :include => :shared_sessions, 
          :conditions => ["shared_sessions.session_hash = ?", session_hash])
  end
end
Easy peasy.

4. Testing time

Run the migration, fire up a mongrel instance on 3000, hit the appropriate vhost, login to your PHP app and go to /some_resource. With any luck you'll be able to hit the /some_resource path with a logged in user.

Now then, it's not quite that simple

The astute ones will notice "Hey what happens if I login from PHP, see /some_resource, then come back directly to /some_resource in future - I could do this at any point in the future, it won't log me out". Exactly, you can handle this one of two ways. Either some nasty cron job thing to clear out the SharedSessions table, or do it as part of the load_user filter in the rails app - ie before restoring the user, SharedSession.delete_all("updated_at < DATE_ADD(NOW(), INTERVAL -15 MINUTES)") or whatever matches your current PHP session timeout settings. You also probably want to do some hash of the user agent, ip address etc and store this away in the shared_session table, then check against it whenever you're finding if a user exists, to try to eliminate cookie theft.

The fine print

It's pretty simple and it works in testing... YMMV. Test the hell out of it in your own application.

Read More

Tips of the day - Query Trace and Equality

07 March, 2008

Tip #1 Query Trace So you're profiling your application, cutting down your SQL queries, looking through the logs - "argh where did that query come from ?!" you say to yourself. Then you remember what Luke G said at the last Toronto Rails Project nite - check out Query Trace. Oh how this has made my life so much better. It tells you the stack trace at the point the query was executed, colorised nicely so you don't go blind tailing your log files. Here's a very simple example so you get the idea.. Query trace output Get the plugin from here https://terralien.devguard.com/svn/projects/plugins/query_trace/README Tip #2 Object equality vs checking id's When checking for ownership or association between objects, be careful you're not checking for equality of the objects. For example "did person x create this order y" the temptation is simply to go "if person == order.creator", where you're checking the objects themselves. Careful! As this is actually loading up the creator of the order if it's not already loaded (SELECT * FROM people WHERE person.id = x). Simply check if person.id = order.creator_id, as this won't require the order's creator to be loaded, eliminating one less hit to the DB. Little things like this littered through an application can start really slowing things down if you're not careful.

Read More

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License.