Archive for April, 2007

Probably?

Sinking feeling
noun
1 The sensation felt in the middle of one’s brain when one comes across a comment like this in front of a large, otherwise uncommented function in one’s month’s old code:

# This is probably an error

Comments Off

chris on April 23rd 2007 in /dev/random

More Trivial Scripting with Ruby

Last Friday, in Trivial Scripting with Ruby on O'Reilly Ruby, Gregory Brown demonstrated a two-line example of the ease with which simple utility scripts can be created from Ruby. In his case a script that takes a filepath and returns the contents with all HTML entities escaped.

I like it, but I don't have any use for this operating on a per-file basis. More useful to me is being able to pass in the HTML text via command line args:

RUBY:
  1. #!/usr/bin/env ruby
  2.  
  3. require "cgi"
  4. ARGV.each { |x| puts CGI.escapeHTML( x ) }

I saved this as esc.rb. To use:

Sagarmatha:~/Documents/utilityscripts chris$ ./esc.rb "<em>Hello & World</em>"
&lt;em&gt;Hello &amp; World&lt;/em&gt;

2 Comments »

chris on April 19th 2007 in /dev/ruby

Updating MySQL Gem to 2.7

While updating my installed gems this evening I ran into an issue with the mysql-2.7 gem:

ERROR: While executing gem ... (Gem::Installer::ExtensionBuildError)
ERROR: Failed to build gem native extension.

ruby extconf.rb update
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lm... yes
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lz... yes
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lsocket... no
checking for mysql_query() in -lmysqlclient... no
checking for main() in -lnsl... no
checking for mysql_query() in -lmysqlclient... no

The solution was to explicitly tell gem where the local MySQL install is:

Sagarmatha:~ chris$ which mysql
/usr/local/mysql/bin/mysql

Sagarmatha:~ chris$ sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql

Caveat: Note the double -- between mysql and --with. That's not a typo (though it may look like a single dash in this page in some browsers).

4 Comments »

chris on April 19th 2007 in /dev/ruby

Centering an image CSS-style

Today a simple little tip from an unglamouruos, oft-maligned language: CSS.

In the olden days we all centered our images using ye olde <center></center> tags and it was goode. But then along came HTML 4.0 and center was deprecated. So now what?

Well, we used center anyway because who really cares about validation? C'mon, admit it, you still use center, maybe when no one's looking? Its not like browsers are going to stop supporting that tag any time anyway, at least not during my lifespan (though come to think of it we have done away with blink....)

Well center no more, nu-skool img centering to the rescue:

CSS:
  1. img {
  2.     margin: 10px auto 10px auto;
  3. }

This sticks a 10 pixel margin top and bottom of your images and centers them left and right within whatever container they're in. Ta da. Impressed?

(And if you're thinking "Well duhhh" after that, go read Reg and chew on some of that, you....)

Comments Off

chris on April 17th 2007 in /dev/random

Google Data API and Cocoa

Google continues to build up its support for, and integration with, Mac OS by releasing the Google Data APIs Objective-C Library, which effectively allows Cocoa developers to support the Google API within any application:

Google Calendar, Google Base, Google Spreadsheets, and generic Atom feeds like Blogger are supported now in the framework, with access to more services already in development.

The Official Google Mac Blog has an example program demonstrating an interface to Google Calendar. The icing on the cake, though, is full support for bindings. Pretty spiffy indeed.

Comments Off

chris on April 17th 2007 in /dev/random

in_place_editor_field as a textarea

You want to use in-place editing but you've got a large amount of text and the default textfield created by in_place_editor_field just isn't large enough? Set the rows property:

RUBY:
  1. <%= @activity_item_note = note; in_place_editor_field :activity_item_note, :note, {}, :url => { :controller => 'activity_item_note', :action => 'set_note_text', :id => note.id }, :rows => 4 %>

When the rows property is set to any value greater than 1, in_place_editor_field renders a textarea instead of a textfield.

Comments Off

chris on April 13th 2007 in /dev/rails

in_place_edit_for, in_place_editor_field and Complex Cases

In-place editing of content is a very cool feature and for the most part dead-simple to do in Rails. Unfortunately all the examples around, including the ones in Rails Recipes, assume you'll be implementing this functionality in only the simplest of cases, usually when displaying just that editable data on the page.

In my case I have much more complex requirements - an instance of an event can have many notes attached to the event. If the author of the note is viewing the event they should be able to edit any notes they've written, and edit them in the page using in_place_editor_field.

In this instance the controller for the notes is different than the controller for the page.

Here's how I finally managed to get it to work, using the editing of a note title as an example.

First, add the following line to the note controller:

RUBY:
  1. class ActivityItemNoteController <ApplicationController
  2.     in_place_edit_for :activity_item_note, :title

This automagically sets up a function in the controller called set_activity_item_note_title for us.

Second, in the view, which is app/views/activity/show.rhtml and thus controlled by the ActivityController I display all notes via:

RUBY:
  1. <% activity_item.activity_item_notes.each do |note| %>
  2. ...
  3. <% end %>

At this point every other example of in_place_editor_field would tell you to add the following to your page to create an in-place editor:

RUBY:
  1. <%= in_place_editor_for :note, :title %>

or some variant of that (or something even worse if the author is building their example off of Rail's scaffolding). But that won't work in this case for many, many reasons which you have probably already discovered for yourself if you're reading this.

So, third, I customized the in_place_editor_for like so:

RUBY:
  1. <%= @activity_item_note = note; in_place_editor_field :activity_item_note, :title, {}, :url => { :controller => 'activity_item_note', :action => 'set_activity_item_note_title', :id => note.id } %>

@activity_item_note = note; - set our iteration as an instance variable instead, since in_place_editor_for requires one of these to work (sigh).

:title - define the property to be edited.

:url => { :controller => 'activity_item_note', :action => 'set_activity_item_note_title', :id => note.id } - take back control of the controller and point it to the one that should handle the edit. Add the name of the method and make sure the id of the note being edited is in there as well.

And that does it.

Warning: Because we're passing the id in the URL there's pretty much nothing in this to stop someone from hijacking the URL, injecting their own id's and running rampant through the database, mucking with titles as they see fit. The default set_activity_item_note_title created when I defined in_place_edit_for :activity_item_note, :title has no provision to manage this sort of authentication. As such it is probably a good idea to wrap the auto-generated functions with your own code to manage authentication, something like:

RUBY:
  1. note = ActivityItemNote.find( params[:id] )
  2.   if @user.id == note.user_id
  3.     # pass along to built-in 'set_activity_item_note_title' here
  4.   else
  5.     # scold the user for trying to edit someone else's note
  6.   end

In my case a simple version of this is:

RUBY:
  1. def set_note_title()
  2.     begin
  3.       note = ActivityItemNote.find( params[:id] )
  4.       if nil != note
  5.         note.user_id == @user.id ? set_activity_item_note_title : render( :text => note.title )
  6.       end
  7.     rescue
  8.       render :text => ' --- '
  9.     end
  10.   end

2 Comments »

chris on April 13th 2007 in /dev/rails

Polymorphic Associations

It's been at least a week since something in Rails made me stop and think "whoa - cool!" but today it was polymorphic associations. I am impressed indeed.

Good examples of how to implement are a bit hard to come by though. Polymorphic Association in Rails by Manik was the clearest for me, particularly his simple demonstration in the console.

Intuitively this feels like a feature that it might be easy to abuse. Has anyone done any performance benchmarking on how linking relationships like this might impact an application?

Comments Off

chris on April 10th 2007 in /dev/rails

Ruby Jobs

Looking for a job working with Ruby and/or Rails?

http://jobs.rubynow.com/

Even better, there's an RSS feed: http://jobs.rubynow.com/rss/feed.xml

(Note to my current co-workers: no worries, I'm not looking, honest)

(Thanks Sam!)

Comments Off

chris on April 9th 2007 in /dev/rails, /dev/ruby

English-friendly timespan in Rails

Awhile ago I was looking for a function that would convert a number of seconds into a human-readable timespan string. For instance: convert 86400 into 1 day and 172800 into 2 days, accomodating intervals ranging from weeks to minutes.

I didn't find one. Instead, this is what I came up with this, which at its fanciest will output something like 2 days, 14 hours and 15 mins.

RUBY:
  1. # Takes a period of time in seconds and returns it in human-readable form (down to minutes)
  2. def time_period_to_s time_period       
  3.   out_str = ''
  4.      
  5.   interval_array = [ [:weeks, 604800], [:days, 86400], [:hours, 3600], [:mins, 60] ]
  6.   interval_array.each do |sub|
  7.     if time_period>= sub[1] then
  8.       time_val, time_period = time_period.divmod( sub[1] )
  9.          
  10.       time_val == 1 ? name = sub[0].to_s.singularize : name = sub[0].to_s
  11.            
  12.       ( sub[0] != :mins ? out_str += ", " : out_str += " and " ) if out_str != ''
  13.       out_str += time_val.to_s + " #{name}"
  14.     end
  15.   end
  16.  
  17.   return out_str 
  18. end

Obviously it's hard-coded only to support english and ignores seconds (too fine-grained for me) but over-coming either of those limitations should be fairly straight-forward.

Update: I terminated the upper value at weeks because things get complicated when we get to months. We can all agree that a day is 24 hours, a week is 7 days, but how long is a month? Not four weeks, not five weeks.... Predictability dies at months, where the actual timespan becomes relevant, and that's more work than is worthwhile at this point. Feel free to embrace and extend :)

2 Comments »

chris on April 4th 2007 in /dev/rails, /dev/ruby