Logo

Peonies are luscious.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

Peonies are my favorite flower, and even though I've resolved to live frugally these days, I couldn't resist picking up a bunch of deeply pink ones at the Greenmarket yesterday.

I love their dense, luxurious petals, and I like to emphasize that lushness by arranging them in tight bunches - this week, I've chosen a cute little creamer to use as a vase. Which is how this post is food-related.

What's your favorite flower, and how do you like to arrange them?

Do you peel your rhubarb?

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

I've seen recipes that mention it, and ones that don't. I've mostly done it, but sometimes I skip the step to save time. So, my question for you all is: do you peel your rhubarb? Do you find a major difference in texture when you do? Is it worth the time?

What's in your fridge?

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

Back when eGullet used to host their weekly food blog (I contributed twice, in 2006 and 2007), one of the traditions was for the week's featured blogger to invite us into their refrigerator. And if the blogger didn't comply within the first day or so, people practically revolted!

I might be exaggerating just a tad, but people's appetite for that glimpse into the fridge never failed to amaze me. So, since my fridge is chockablock full of late-spring goodies right now, I thought it might be time to give you all a little tour...

On the top shelf, we've got my Brita, some cranberry juice (for visitors who like a vodka cran, or a cosmo), my current jar of pickled ramps, a jar of Rick's Picks, a tub of Fage yogurt, Diet Coke (it fuels me), leftover Vietnamese food, Sriracha, some cold chicken (in the tinfoil) and this week's salad dressing (in the bowl.).

On the middle shelf, there's tonic water (diet and regular), some Magic Hat brought over by a book club member on Thursday, lemons & limes, some more Vietnamese leftovers (and slab bacon perched on top), and a line-up of jars holding strawberry-rhubarb compote and more pickled ramps.

On the bottom shelf, there are some strawberries (not local - a freebie from FreshDirect), romaine lettuce, rhubarb, spring garlic, and eggs! In the drawer we've got onions, snap peas, cucumbers, shallots, scallions...and I think that's it. The door is an assortment of various condiments, pickles, vinegars and oils (they stay fresh longer in the fridge) and cheese. Oh, and garlic!

So, what's in your fridge?

Spring's sharp bite - and a bargain to boot.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

Radishes aren't everyone's cup of tea - and, I admit, they're not at the top of my list of produce to get worked up over. That said, they add a delicious, peppery bite to salads, are delicious with butter, bread and salt, and, perhaps best of all - they're an insane bargain.

Local radishes from small farmers? $1 a bunch. ONE DOLLAR. Just thought that all of you who think buying local and sustainable is out of reach, budget-wise, should know about this. Not that you can live on radishes alone, but it's a start.

Cheating on Paris.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

About six months before I launched Queenie Takes Manhattan, Louisa and I took a two-week trip to Europe. In addition to being a two-week long confirmation of the fact that we were destined to be best friends (we traveled together really, really well), it was a fantastic tour of some of Europe's most beautiful spots (Épernay excepted, though it gets a pass for the fantastic, sparkly hooch.).

We started off with five days in Prague, and knew we wanted to spend time in Champagne and Paris - but had no stop in the middle. Louisa wasn't terribly keen on Germany, so I did a little research and decided we would spend three days in Strasbourg as a way to break the journey from Prague to Reims.

We loved Prague, we had a fantastic, posh, tipsy time in Champagne, and Paris is Paris - but Strasbourg took us by surprise. It's an amazing place. Tiny but cultured (thanks in no small part to the university and the EU Parliament and Court of Human Rights), it's a gorgeous little mashup of French and German culture - luxurious but down-to-earth, fashionable but practical. It's flat and walkable, with a great tram system and miles upon miles of bike paths.

We had our best meal of the trip at Chez Yvonne, a vinstub (a sort of wine tavern) on one of the old town's tiny cobblestone streets. We also had some of the best pastry of our lives (Thanks, Pâtisserie Christian!), stayed in one of the most unexpectedly adorable hotels, and woke up each morning to the bells chiming in the pink - PINK! - cathedral.

In short, we found Strasbourg to be a most magical place - I'm still toying with the idea of moving there - and I would love to go back as soon as possible.

Barring that, I comb the interwebs for doses of Strasbourg-eosity whenever possible. This morning I came across this Flickr set (courtesy of Mike G. K.), and was promptly whisked away by a fantasy in which I decorate an apartment in central Strasbourg with finds from Paris' flea markets and some well-chosen Ikea bits and bobs, and then spend my days wandering Strasbourg's streets and writing about the city's magical charms. And, of course, get paid very, very well for it all. Sigh.

Thanks, Mike.

Photos of everything but the pastry courtesy of Mike G. K.'s Flickr stream.

Paperclip sample app part 3: saving file attachments in a database BLOB column

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

In part 1 of this series, I showed how to create a simple Rails web site that uses the Paperclip plugin from Thoughtbot to upload and display image files. Then in part 2, I went on to change the sample app to download the image files through a Rails controller and not just through a direct call to Apache. This would be useful if you wanted to implement security for file attachments or for a variety of other reasons.

This time I’d like to show how to modify the same sample application to save the file attachments in a database BLOB column, instead of on your web server’s file system. To jump ahead and just get the working code, look at the “part3” folder in the github repo: http://github.com/patshaughnessy/paperclip-sample-app.

But before we actually work on the sample app, a disclaimer: Don’t try this at home! Serving file content directly from the file system via Apache or some other web server will always be faster and simpler than loading the file attachments from a database table… Apache and other web servers were designed to load and serve files quickly, and there’s normally no need to issue an expensive SQL query or to make another network connection to a database server just to send files to a web browser.

So why in the world would you ever want to pay the extra performance penalty and move the files into a database table? Here are a couple of reasons:

  1. Your client or employer wants you to. Some companies insist on using a commercial, “enterprise” RDMS system to save file contents for one reason or another. My employer, for example, has many years of experience using Oracle and is comfortable managing large numbers of files that are stored in an Oracle table, while the thought of managing, replicating, backing up, etc., files that are simply saved on a Linux file system seems much more complex and unfamiliar.
  2. Security. If you need to encrypt the contents of super-secret file attachments, storing them in a database might be an easier solution if you’re willing to spend money on a database server like Oracle. And database encryption aside, generally information in a database server can be more easily protected and audited than files on your web server's file system can be.

Anyway, let’s move on and actually change the sample app to save the files in a BLOB column. The first thing we will need to do is to use the version of Paperclip that I modified; the actual Paperclip plugin from Thoughtbot does not support storing files in a BLOB column. I added some code to Paperclip – a new “storage module” – to make this possible. See my code changes to learn more.

So let’s delete the original plugin and install my version:

$ cd /path/to/paperclip-sample-app
$ rm -rf vendor/plugins/paperclip
$ ./script/plugin install git://github.com/patshaughnessy/paperclip.git

Now that we have the modified plugin installed, let’s go ahead and create the BLOB columns that we will use to save the files. I tried to design the database storage module to be easy to use; one of the decisions I made was around what these BLOB columns should be called. I decided by default to use “[attachment]_file” as the name for the primary file attachment, and “[attachment]_[style]_file” for the other styles. If you want to use other column names, you just need to specify the names in the call to “has_attached_file” in the model. See my usage post for more info.

For this sample app I’ll go ahead and use the default column names: “avatar_file,” “avatar_small_file” and “avatar_thumb_file.” Here’s how to create those columns for a MySQL database. First create a new migration as usual:

$ ./script/generate migration add_attachments_blob_avatar_to_user
exists  db/migrate
create  db/migrate/20090528173400_add_attachments_blob_avatar_to_user.rb

… and then edit the new migration file and add the bolded code to it:

class AddAttachmentsBlobAvatarToUser < ActiveRecord::Migration
  def self.up
    execute 'ALTER TABLE users ADD COLUMN avatar_file LONGBLOB'
    execute 'ALTER TABLE users ADD COLUMN avatar_small_file LONGBLOB'
    execute 'ALTER TABLE users ADD COLUMN avatar_thumb_file LONGBLOB'
  end

  def self.down
    remove_column :users, :avatar_file
    remove_column :users, :avatar_small_file
    remove_column :users, :avatar_thumb_file
  end
end

Normally to create a BLOB column you would use “add_column :users, :avatar_file, :binary.” This would work fine for Oracle and other database servers. MySQL, however, supports four different types of BLOBs: TINYBLOB (256 bytes), BLOB (64k bytes), MEDIUMBLOB (16MB) and LONGBLOB (4GB). (See http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html for more information.) If we used the Rails migrations :binary column type, then we would get normal BLOBs and have an upper limit for the file attachment size of 64k, which is not normally enough. Unfortunately, there’s no way to specify LONGBLOB for MySQL using Rails migrations, so you have to use the “execute” migration and write an actual SQL statement to add the column.

Next go ahead and run your migrations and create the new columns:

$ rake db:migrate
(in /path/to/paperclip-sample-app)
==  AddAttachmentsBlobAvatarToUser: migrating =================================
-- execute("ALTER TABLE users ADD COLUMN avatar_file LONGBLOB")
   -> 0.0585s
-- execute("ALTER TABLE users ADD COLUMN avatar_small_file LONGBLOB")
   -> 0.0266s
-- execute("ALTER TABLE users ADD COLUMN avatar_thumb_file LONGBLOB")
   -> 0.0116s
==  AddAttachmentsBlobAvatarToUser: migrated (0.0973s) ========================

Now we just need to tell Paperclip to use database storage instead of the default file system storage and we’re ready to try our app and see if it saves the files into the new BLOB columns. Add the bolded parameter to has_attached_file in the User model:

class User < ActiveRecord::Base
  has_attached_file :avatar,
                    :storage => :database,
                    :styles => { :thumb => "75x75>", :small => "150x150>" },
                    :url => '/:class/:id/:attachment?style=:style'
end

Note that I also removed the “:path” parameter; this value would be ignored by the database storage module anyway since the files will be stored in the DB. Let’s try it out! Start up the sample app, and re-edit a user record to upload a new image file:

Select a file, click “Update” to submit the form and the file will be processed by ImageMagick, and saved into our new BLOB columns by the database storage module in Paperclip…

What? Where’s the image? It turns out that we still need to make a code change to the UsersController to download the image file from the BLOB column instead of from the file system. I’ll get to this in a moment. But first, let’s look at the console and see if the new files were saved into the database properly:

$ ./script/console 
Loading development environment (Rails 2.3.2)
>> User.first
=> #<User id: 1, name: "Mickey Mouse", email: "mickey@disney.com",
created_at: "2009-05-28 17:27:00", updated_at: "2009-05-28 17:37:42",
avatar_file_name: "mickey-mouse.jpg", avatar_content_type: "image/jpeg",
avatar_file_size: 137233, avatar_updated_at: "2009-05-28 17:37:42",
avatar_file: "\377???JFIF\000\001\002\001\001h\001h\000\000\377?\021\b\002\210\001?\001\021\000\002\021\001\003\021\001\377?\204\000\001\001\001\001\001\001\001...",
avatar_small_file: "\377???JFIF\000\001\001\001\001h\001h\000\000\377?C\000\003\002\002\002\002\002\003\002\002\002\003\003\003\003\004\006\004\004\004\004\004\b\006\006\005\006...",
avatar_thumb_file: "\377???JFIF\000\001\001\001\001h\001h\000\000\377?C\000\003\002\002\002\002\002\003\002\002\002\003\003\003\003\004\006\004\004\004\004\004\b\006\006\005\006...">

Here you can see the three new BLOB columns, avatar_file, avatar_small_file and avatar_medium_file, and the first few bytes of each column’s value. In fact, if you’re a real geek you’ll notice that the first few bytes contain “JFIF,” which is probably the image file type specification (not sure)… so we know we are seeing the binary contents of the three versions of the Mickey image here. Great!

Actually, not so great: there’s a subtle problem here we need to worry about. I actually typed in a very simple ActiveRecord command, “User.first,” and it loaded all three of the image files’ contents into memory just so that I could inspect the value of the user record in the console. This was convenient now, since I was actually interested in knowing whether or not each of the files was saved properly in the DB. However, this is potentially a big performance problem in general. Imagine if the files were very large… it could take a long time for all 3 of the files to be fetched by a SQL query and returned to the Rails ActiveRecord object. Do I really want or need this to happen every time I access a User record? Usually when I load a User record it’s just because I need to check the value of one of the metadata columns, like the user’s name, email address or something else. And if I do need one of the files, why should I have to load all three files? Spending the time required to load the file contents for each image style is a big performance penalty that isn’t usually necessary.

The solution I came up for this problem was to enable Paperclip to add a method to your model class called “select_without_file_columns_for” that you can use as a named scope or, even better, a default scope. It returns a :select scope hash that will exclude the BLOB columns from the SQL query that ActiveRecord issues to load each record. If you’re using Rails 2.3 or higher, you can use select_without_file_columns_for as a default scope in your model like this:

class User < ActiveRecord::Base
  has_attached_file :avatar, :storage => :database,
                    :styles => { :thumb => "75x75>", :small => "150x150>" },
                    :url => '/:class/:id/:attachment?style=:style'
  default_scope select_without_file_columns_for(:avatar)
end

To learn more about default scopes and to see a couple of other examples, read this: http://ryandaigle.com/articles/2008/11/18/what-s-new-in-edge-rails-default-scoping … or http://m.onkey.org/2009/3/24/default-scopes-and-inheritance-to-the-rescue. Let’s see how this works in the console again after adding the default scope:

$ ./script/console 
Loading development environment (Rails 2.3.2)
>> User.first
=> #<User id: 1, name: "Mickey Mouse", email: "mickey@disney.com",
created_at: "2009-05-28 17:27:00", updated_at: "2009-05-28 17:37:42",
avatar_file_name: "mickey-mouse.jpg", avatar_content_type: "image/jpeg",
avatar_file_size: 137233, avatar_updated_at: "2009-05-28 17:37:42">

Cool. Now the BLOB columns are not displayed. “Default scope” refers to the fact that the SQL used by ActiveRecord by default to load records is automatically changed. I didn’t have to pay the price of loading each of the files, and I was still able to load all of the other User columns using ActiveRecord the way I normally would. To see what happened, execute the “select_without_file_columns_for” method directly in the console:

>> User.select_without_file_columns_for :avatar
=> {:select=>"id,name,email,created_at,updated_at,avatar_file_name,
  avatar_content_type,avatar_file_size,avatar_updated_at"}

It‘s a lot more common to use a default or named scope with :conditions (to modify the WHERE clause) or :order (to modify the ORDER BY clause) but in this case I’ve used :select to specify which columns should be loaded by ActiveRecord (the SELECT portion of the SQL). If you look at the hash, you’ll see all of the User columns listed, except for avatar_file, avatar_small_file and avatar_thumb_file.

If you’re using Rails 2.2 or earlier default scope is not available yet, and you will need to use a named scope, like this:

class User < ActiveRecord::Base
  has_attached_file :avatar,
                    :storage => :database,
                    :styles => { :thumb => "75x75>", :small => "150x150>" },
                    :url => '/:class/:id/:attachment?style=:style'
  named_scope :without_file_data, select_without_file_columns_for(:avatar)
end

And you will need to use the named scope explicitly to avoid loading the files, like this:

$ ./script/console 
Loading development environment (Rails 2.3.2)
>> User.without_file_data.first
=> #<User id: 1, name: "Mickey Mouse", email: "mickey@disney.com",
created_at: "2009-05-30 12:14:03", updated_at: "2009-05-30 12:14:03",
avatar_file_name: "mickey-mouse.jpg", avatar_content_type: "image/jpeg",
avatar_file_size: 137233, avatar_updated_at: "2009-05-30 12:14:03">

A good way to understand exactly what ActiveRecord is doing is to use a Ruby trick and open up the User class and add some debug code to it. Try entering this code into your console:

>> class User < ActiveRecord::Base
>>   def self.find_by_sql(sql)
>>     puts "DEBUG: #{sql}"
>>     super
>>   end
>> end
=> nil

What this code does is open up our User model class, and override the “find_by_sql” ActiveRecord method to display the SQL statement before calling the original base class method to execute it. Find_by_sql is the method that the various different ActiveRecord find methods all call once they have constructed a SQL statement. For example, find :first, find :all, first, last… all of these eventually call find_by_sql. Assuming we have the version of User with the named_scope, we can see what SQL statements are issued with or without the select_without_file_columns_for scope:

>> User.first
DEBUG: SELECT * FROM `users`  LIMIT 1
=> #<User id: 1, name: "Mickey Mouse", email: "mickey@disney.com",
created_at: "2009-05-28 17:27:00", updated_at: "2009-05-28 17:37:42",
avatar_file_name: "mickey-mouse.jpg", avatar_content_type: "image/jpeg",
avatar_file_size: 137233, avatar_updated_at: "2009-05-28 17:37:42",
avatar_file: "\377???JFIF\000\001\002\001\001h\001h\000\000\377?\021\b\002\210\001?\001\021\000\002\021\001\003\021\001\377?\204\000\001\001\001\001\001\001\001...",
avatar_small_file: "\377???JFIF\000\001\001\001\001h\001h\000\000\377?C\000\003\002\002\002\002\002\003\002\002\002\003\003\003\003\004\006\004\004\004\004\004\b\006\006\005\006...",
avatar_thumb_file: "\377???JFIF\000\001\001\001\001h\001h\000\000\377?C\000\003\002\002\002\002\002\003\002\002\002\003\003\003\003\004\006\004\004\004\004\004\b\006\006\005\006...">
>> User.without_file_data.first
DEBUG: SELECT id,name,email,created_at,updated_at,avatar_file_name,
  avatar_content_type, avatar_file_size,avatar_updated_at FROM `users` LIMIT 1
=> #<User id: 1, name: "Mickey Mouse", email: "mickey@disney.com",
created_at: "2009-05-28 17:27:00", updated_at: "2009-05-28 17:37:42",
avatar_file_name: "mickey-mouse.jpg", avatar_content_type: "image/jpeg",
avatar_file_size: 137233, avatar_updated_at: "2009-05-28 17:37:42">

Here we can see that ActiveRecord will load all of the User columns that are listed above in the hash we pass to named_scope… all of the columns except for the BLOB columns. This is different from what ActiveRecord does by default, which is a simple SELECT * FROM …. statement.

Enough about ActiveRecord internals… let’s get back to the sample app and finish it up:

So why didn’t the image appear here properly? The reason is that in UsersController I’m still using the code that accesses the file on the file system and streams it to the client using send_file (see my last post for more info):

def avatars
    user = User.find(params[:id])
    style = params[:style] ? params[:style] : 'original'
    send_file user.avatar.path(style),
              :type => user.avatar_content_type
  end

Obviously send_file is no longer going to work for us. Instead we need to use a similar function in ActionController::Streaming called send_data, which takes the binary data directly as a parameter instead of a file. And to access the file’s contents, I’ve added a method called “file_contents” to Paperclip that returns the actual file contents for the given style, or for the original style by default. Here’s how to put it all together; replace the “avatars” method in UsersController with this new version instead:

def avatars
    user = User.find(params[:id])
    style = params[:style] ? params[:style] : 'original'
    send_data user.avatar.file_contents(style),
              :type => user.avatar_content_type
  end

Only the line in bold has changed. We just call user.avatar.file_contents, pass in the specified style and then pass along the data to send_data. If you restart the app and refresh your browser, now you should see the image again:

Now we are seeing the binary image file data loaded from the BLOB column by ActiveRecord and streamed down to the browser by send_data.

One last detail about this: since usually everyone will use the same controller code to load the file contents for a given style from the BLOB, and then pass it along to send_data, I enabled Paperclip to add another utility method, this time to your controller, to make this even easier:

class UsersController < ApplicationController
  downloads_files_for :user, :avatar
etc…

If you call “downloads_files_for” from your controller like this and specify the model and file attachment, it will automatically generate the correct controller method for you, and call it “avatars” or whatever the plural version of your attachment name is. I chose the name to make it easy and natural to create a route to it in routes.rb. No need to even think about send_data or how to get the file contents from Paperclip at all! Nothing could be simpler. However, if you need to implement security or some other business rules around downloading files, then you might need to add that business logic to the “avatars” method above. Either way, it’s very simple.

Being pixel perfect - Part 11 (top developer tools for front-end development)

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

Which developer tools do you use to develop high quality front-end?

Here are some of my favorites:

  1. Web Developer (Update: June 3, 2009 >>> removed MeasureIt and Resize Window from the list. Web Developer has a ruler (under Miscellaneous tab) and window resize capability too)
  2. Firebug
  3. Yslow
  4. PixelPerfect
  5. CSS viewer
  6. Extended Statusbar
  7. uitest.com - HTML/CSS validation, accessibility checks

Playing with Watir - File Upload/Download component

about 1 year ago | Amit Kumar: RubyizednRailified

In my last post I talked about WATIR integration with Rspec.

In our project, we had excel report download component. The challenge with Watir was to be able to download the excel file, save it and validate data against DB. Thanks to David Brown for his Excel Interface class library which is easy to implement. Next thing was to be able to save the file at any given location (always). None of the documented steps worked. The autoit dll supported by Watir was at the rescue. Au3Info.exe helps to identify IE control IDs. The following code snippet explains the rest:



After conquering file download, next was file upload. It was much easier coz Au3Info.exe was always their to figure IE control IDs. Using AutoIt documentation simplified it further.



WATIR rocks !!

The TED Commandments

about 1 year ago | Erika Santos: Santos on Technology and Life

I've seen many presentations on interesting material being delivered in not so interesting ways. It's always a bummer. But I'm yet to have this kind of experience with a TED speech. Sure, TED speakers are accomplished professionals professionals; but I think you all know that impressive accomplishments are not necessarily accompanied by impressive communication skills.

I ran into some ting today that made me think that the caliber of TED's speeches may have something to do with TED's recipe for speech delivery. Every person scheduled to speak at TED apparently receives a rock in the mail, with the TED speakers' guidelines printed on it.


1. Thou shalt not simply trot out thy usual shtick
2. Thou shalt dream a great dream, or show forth a wondrous new thing, or share something thou hast never shared before
3. Thou shalt reveal thy curiosity and thy passion
4. Thou shalt tell a story
5. Thou shalt freely comment on the utterances of other speakers for the sake of blessed connection and exquisite controversy
6. Thou shalt not flaunt thine Ego. Be thou vulnerable. Speak of thy failure as well as thy success.
7. Thou shalt not sell from the stage: neither thy company, thy goods, thy writings, nor thy desperate need for funding; lest thou be cast aside into outer darkness.
8. Thou shalt remember all the while: laughter is good.
9. Thou shalt not read thy speech.
10. Thou shalt not steal the time of them that follow thee.


My favorite commandments are 1, 3, 4 and 5. I hope you put them to good use!

Being pixel perfect - Part 10 (new brand guidelines are available now!)

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

ur new brand guidelines are available now. And the best part isn't just the slick/open look-and-feel, but also that it applies to both internal and external digital properties.

Creating one brand guideline for all (internal and external) digital properties is a huge step for us. Other firms that do this already might consider it common sense but in our firm, where a thousand flowers are allowed/encouraged to bloom, such governance is challenging.

I'm excited about it as it'll help our:
1) end users experience these applications in a consistent way
2) development teams us with:
- reuse of templates, icons, styles, techniques, experts, tools
- familiarity of applying one brand to app apps they develop

Charcuterie, chez moi.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

It was pretty dang warm here on Friday. Don't get me wrong - this spate of summer-like weather we've been having is very, very welcome - not to mention good for Memorial Day business at the local beaches. That said, my motivation to actually cook tends to dwindle as the temperature rises. So, for lunch, I decided to break out the charcuterie.

Pâté de campagne is one of my favorite types of charcuterie - I tend to prefer the more rustic versions, where the meat is chopped as opposed to pureed, and boldly flavored with cognac and black pepper. Of course, going for pâtés made of pork (pâté de grandmère is another good example) is also a more economical option than springing for those made with duck and foie gras.

Lately, I've been favoring Les Trois Petits Cochons for my charcuterie needs. They're based in Brooklyn and produce a full line of delectable charcuterie, including vegetable terrine and the aforementioned pate de campagne.

When I got home from the Greenmarket (where I'd bought a loaf of whole wheat sourdough from one of the bakery stands), I cut a few slices of pate, spooned a few pickled ramps out of their jar, sliced the bread and dished out a little whole grain mustard. A little light on the veggies, sure - but who needs salad when you've got pâté? Not I, my friend. Not I.

Being pixel perfect - Part 9 (web template for dev teams)

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

James is developing a web template for dev teams to use as a starting point in their projects.

Using this template will automatically make our products compatible with our brand guidelines...

The template will include HTML/CSS for summary/list views, forms and icons.

What else do you need to get started on your web project?

Read only models in ActiveRecord

about 1 year ago | Amit Kumar: RubyizednRailified

I was working in one of my project, where we were required to connect to 2 databases.

  1. First we had access to do CRUD
  2. Second we were only supposed to READ
For the second DB we wanted to raise exception from Rails, if somebody by accident tried to create/edit. ActiveRecord has this attribute as part of all models already called @readonly. There are definitely few challenges. Here is what I did:

The sweet model:


If somebody tries to add a record:


If someone tries destroy


What if someone uses delete


Rest in peace !!

A city obsessed.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

It's no secret that New York is a city obsessed with food. Be it home-cooked, ordered-in, or eaten-at-a-restaurant, New Yorkers cannot stop talking about their latest food fascination. This year, the biggest trend has been for the affordable and the transportable: banh mi sandwiches.

Sometimes, though, an obsession makes it through the trend phase and winds up a classic. Such is the story of Café Habana's grilled corn. People wait in line for this corn; they eat it on sidwalks, gobble it up greedily, and order more.

Grilled in the husk, then shucked, covered in mayonnaise, rolled in cojita cheese and seasoned with cayenne and lemon juice, it's pretty much one of the best things you've ever tasted. A little sweet, a little rich, a little salty, a little tangy - it's like spicy dessert.

Haven't had it yet? Do it soon.

Oh, and - those of you not lucky enough to live within subway distance? Here's a recipe to make the corn at home.

Cafe Habana
17 Prince Street (at Elizabeth Street)
212.625.2001

Yale University recognizes a prominent social entrepreneur and McKinsey alum

about 1 year ago | Amy Grandov: Technology for Social Innovation

Social entrepreneurship got another boost on Monday when Yale University recognized Ashoka Founder and CEO Bill Drayton with an honorary doctorate. (Bill Drayton launched Ashoka while a consultant with McKinsey's New York office). Ashoka identifies "entrepreneurs" who have innovative, practical ideas for addressing social problems, and provides them with the financial support, professional networks, and guidance to get put their ideas into action.

The Ashoka website describes how the social sector is learning how to compete and succeed from the business world:
"We are in the midst of a rare, fundamental structural change in society: citizens and citizen groups are beginning to operate with the same entrepreneurial and competitive skill that has driven business ahead over the last three centuries. People all around the world are no longer sitting passively idle; they are beginning to see that change can happen and that they can make it happen. The result of this transformation will ultimately be a world where all individuals will be able to spot challenges, address them, and improve their lives."

Though I doubt people have been sitting passively idle until now (a bit of hyperbole), its exciting to watch this shift in mindset. People closest to a problem will often have the best ideas for solutions, and philanthropists are becoming sources of venture capital to make these ideas feasible. Its also encouraging to see business and the social sector start to speak the same language and inspire common ways of approaching problems. Many of the problems we're facing are so complex - global warming, poverty, education reform - that they really require public/private/non-profit partnerships to succeed.

1,001 (ok, two) ways to eat your strawberry-rhubarb compote.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

With vanilla ice cream...

...or with waffles, butter, and a pinch of sugar.

Family time.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

On Friday night, I met up with my brother, Jeremy, at Joe, and we made our way downtown to Pearl Oyster Bar. We arrived at 5:30, a half hour before opening, and there were already about 10 people on line waiting to get in.

When the doors opened at 6:00, we hopped into two seats at the bar and ordered - oysters and a lobster roll for me, clam chowder and a lobster roll for Jer. Few people appreciate food the way my brother does, and he seems to have a special place in his heart for seafood - so it was really fun for me to share his first Pearl experience with him.

The oysters were fantastic - clean and fresh tasting, with just a hint of briny sea. The mignonette sauce was fantastic - bracing and full of tangy shallots - but the cocktail sauce could use a bit more zing. It was warm on Friday night, but the air conditioning was going full-blast, so the weather inside was just right for a bowl of soup.The clam chowder was rich and creamy, filled with bacon and chunks of potato.

And, unsurprisingly, the lobster rolls were amazing, though a tad overdressed with mayo that night.

Jeremy had to head over to the theatre, so we had to forgo dessert, but we agreed that next time we'd try the hot fudge sundae and the strawberry rhubarb pie. Yes, we're definitely related. Like you couldn't tell just by looking at us...

Message / SOA Testing...

about 1 year ago | Riju Kansal: Riju's Thoughts Captured...

Recently I have started working for a testing project in the financial domain. The application we need to test uses a lot messaging architectur {SOA}. So basically a number of systems interact with each other by sending messages to each other and receiving responses in asynchronous fashion.

So automating the testing for the messaging framework is very crucial. We are using a licenced software called Green Hat for this task. In this tool we basically create publishers and subscribers to various Queues. We create XML messages and send them to Publisher Queues and verify the responses using Subscriber Queues or Database calls.

This Green Hat being licenced tool I was wondering if we can find out an open source way of doing this. And I found the following link in the very first search results.

http://www.ibm.com/developerworks/websphere/library/techarticles/0808_vandekuil/0808_vandekuil.html

This is basically using JMeter for the same purpose.

Playing with Watir

about 1 year ago | Amit Kumar: RubyizednRailified

Past few days I have been playing with using Watir in my current project. I bet it has been fun. Watir gives this awesome power for automated testing. Many would argue why not Selenium for that matter. There were few challenges using Selenium:










FeatureWatir/WatijSelenium
Frames and popup supportEasyHas problems
API for database connectivityEasyDoesnt have API support
Multi language (non-ascii character)supportEasyNo
RecorderYesOnly for FF
Integration with RspecEasy to create a test suite. See example below
Cross domain supportYesNo
Ajaxified responsesYesDifficult


One of the fun part was attaching your browser instance to your IRB. The examples here is self sufficient explanation. If not, then watir-console is theie for rescue.

Not to forget the Excel Interface Class, which we used to download an excel report (as part of our project) and match the values against DB records.

The rspec task to run the tests as a suite and also lets you connect to environment specific database:

desc "Run all watir tests "
namespace :spec do
Spec::Rake::SpecTask.new(:watir) do |t|
ENV["WATIR_ENV"] = ENV['env'] ? "#{ENV['env']}" : "development"
t.spec_files = FileList['test/integration/watir/*_spec.rb']
t.spec_opts = ["-fh > public/watir_results.html"]
end
end

From the command prompt you could run:

>> rake spec:watir (runs and connects against development database)
>> rake spec:watir env=qa (runs and connects against qa database)

Lately, a lot of progress has been made on Watir Recorder

Web 2.0 and Collaborative governance

about 1 year ago | Lalatendu Das: Interpretations of Technorealism

Check out Stimuluswatch.org
The site lists all proposed "shovel-ready" projects, where the Obama administration is planning to invest the stimulus money.

OKay...What's new??
It let's people (not just administrators, contractors..but just about anybody who cares) to rate these proposed projects.

Simple, yet effective. Citizens with their knowledge on the local environment, rate these projects on it's viability. Provide comments on it's priority, suggest improvements. In turn, this gives an 'on the ground' perspective to the policy makers sitting in the capitol hill.

A number of critical attributes of such 'collaborative governance' stand out, such as
- Brings in transparency to decision making process involving public spending
- Makes authorities accountable for decisions made
- Harnesses collective intelligence
- Inclusive approach in policy making brings in a positive energy

I wonder if we can extend similar web 2.0 features to bring more transparency in Corporate Governance. In the current economic environment, where the purse strings are tighter than ever, can we go for an inclusive approach in determining where to invest the money on? Can we use this approach in prioritizing projects we pick for execution?

Would like to know what you think...

It's that time again.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

My friends, the day I've been waiting for has finally arrived. Strawberries are here, and all is right with the world.

I took Friday off from work and used the morning to visit the Greenmarket. The Friday market is less crowded than its Saturday incarnation, but there are also proportionately fewer vendors on hand. I strode briskly down the line, checking each and every table for the tell-tale turquoise containers, searching and searching until I spied some out of the corner of my eye.

There were about ten quarts of berries on the table, so I quickly swooped down and claimed two of them. My search over, I calmed down a bit and wandered back through the market, adding a pound of rhubarb and a bouquet of poppies to my haul for the morning.

Strawberries will obviously be far more plentiful next week, so there's no need to be precious about them. But to make my haul last until then, I decided to use most of this first batch to make a double batch of one my favorite springtime treats, strawberry-rhubarb compote.

I've already eaten it on ice cream, over greek yogurt (topped with a drizzle of honey) and, admittedly, straight from the jar. Yeah, I'm uncouth - deal.

Paris, through the eyes of a Parisian.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

For those of you who - like me - just can't get enough of Paris right now, have a gander at Cyril Genty's incredible, inspiring photoblog Un Jour à Paris. Each day he takes and posts a photo of his adopted home, and the results show a far more real, grittier, and more beautiful version of Paris than we typically see on this side of the Atlantic.

As someone whose favorite parts of her own city are typically those where the beauty is cut with a little grit, I am breathless at Cyril's ability to document those same parts of his home.

Many thanks to the blog Inside Out, whose fantastic interview with Cyril pointed me toward his blog, and kickstarted my latest addiction.

Photo courtesy of Un Jour à Paris.

Learning from mistakes

about 1 year ago | Niranjan Sarade: InLoveWithNature

Thomas Edison tried two thousand different materials in search of a filament for the light bulb. When none worked satisfactorily, his assistant complained, "All our work is in vain. We have learned nothing."

Edison replied very confidently, "Oh, we have come a long way and we have learned a lot. We know that there are two thousand elements which we cannot use to make a good light bulb!"

Moral: Always take things positively. You can learn a lot from the mistakes you commit. Actually by commiting mistakes, you are laying a strong foundation before the world. So even if you think you have wasted a big time for that, you have actually saved a huge time of others in future...

Obedient Disciples

about 1 year ago | Niranjan Sarade: InLoveWithNature

One day while they were on their way to a distant town, Guru Gampar fell asleep in the bullock cart they were travelling in. His head rolled from side to side and suddenly his turban slipped from his head and fell on to the road. But as their guru had told them never to do anything without his permission, none of the disciples made a move to get down and pick it up.

When the guru woke up and was told about the loss of his turban he was furious. "Next time anything falls off pick it up at once!" he thundered.

Some time later the bullock dropped its dung and the four foolish disciples leaped down and picked it up. Guru Gampar was horrified. He made a list of the things that could fall off from a moving cart. "Pick up any of these things if they fall," he told them, handing them the list. "Don't pick up anything that is not mentioned here."

Just then the cart lurched violently and Guru Gampar was thrown headlong into a ditch. Guru Gampar yelled to his disciples to pull him out.

"We can't, guruji," said his disciples, sadly. "Your name is not on the list you gave us." Guru Gampar pleaded with them to pull him out, but in vain.

"We know you are testing us, guruji," they told him. "But you can rest assured that we will never disobey you. You told us not pick up anything that was not mentioned in your list and we will not do so."

"Give me the list!" yelled Guru Gampar. They threw him the list and the pen and the guru hastily scrawled his name on it.

Then and then only did the obedient disciples pull their beloved guru out of the ditch and put him back into the cart !

Moral : Obedience has to be backed with Conscience and Prudence, otherwise it becomes just a silly act.

The Winner is...

about 1 year ago | Michael Idinopulos: Transparent Office

A lot of companies ask me whether contests are a good way to spur social software adoption. In my experience, contests can be very effective in generating buzz, awareness, participation, and enthusiasm. They can also be demotivating and marginalizing. It...

What is Unobtrusive javascript ?

about 1 year ago | Niranjan Sarade: InLoveWithNature

In simple words, it is separation of behaviour from the html structure.

Consider the following example :-



The style of this button element, to include the font of its caption, is provided by CSS rules loaded via a stylesheet. But while this declaration does not mix style with structure, it does mix behavior with structure, by including the JavaScript
that is to be executed when the button is clicked as part of the markup of the button element (which in this case, turns something named xyz red upon a click of the button).

For all the same reasons that it is desirable to segregate style and structure within an HTML document, it is also becoming recognized that separation of behavior from structure has just as many, if not more, benefits.

This movement is known as Unobtrusive Javascript.

jQuery is a javascript library which supports this movement. It aims to change the way that web developers fundamentally think about creating rich functionality in their pages. jQuery is generally useful for any page that needs to perform anything but the most trivial of JavaScript operations, but is also strongly focused on enabling page authors to employ the concept of Unobtrusive JavaScript within their pages. With this approach, behavior is separated from structure in the same way that CSS separates style from structure, achieving better page organization and increased code versatility.

How to use dates in Rails when your database stores a string

about 1 year ago | Alex Rothenberg: Common Sense Software

When working with Rails there's a lot of magic that happens behind the scenes to make it easy to do complex things. Most of the time you don't need to know how that "magic" works but there are times when things don't work as expected and its helpful to dig in and understand what Rails is doing under the covers so you can change how it works. Did I just say "change how Rails works"?!? I did! Rails is opinionated software that seeks to lead you down the golden path but there are legitimate times when you have to veer off that path and Rails lets you do so. I find this most often happens to me when I'm dealing with an existing legacy database which is not setup as Rails would like.

Today I'm going to go through an example that happened to me recently when I had an existing database that stored some dates in a text column but I needed to treat them as dates in my UI. I couldn't change the type of that column as there was another legacy application that expected it to be text.

Using Dates the Rails Way

First let's look at how easy it is to work with dates when you can follow the Rails Way. Let's create a new project and add a scaffolded Person object with a date attribute called birthday.


rails date_select_example
cd date_select_example
script/generate scaffold person name:string birthday:date
rake db:migrate


Now if we hit the site and try to create a new person we see a screen like this



And when you click "Create"



Exactly what you want with almost no code in the view and none in the model. I did make a minor edit to the view so we would get 1960 in the year select by adding :start_year=>1900 (a full documentation of date_select options are available here)


#app/views/people/new.html.erb
<h1>New person
<% form_for(@person) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :birthday %><br />
<%= f.date_select :birthday, :start_year=>1900 %>
</p>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>

<%= link_to 'Back', people_path %>


and

#app/models/person.rb
class Person < ActiveRecord::Base
end


Errors when storing as text in the database

Now what happens when you run into a case where the date is stored as a string in the database. Let's say we have an "anniversary" attribute stored as a string that we want to treat the same way as we did birthday. We create the migration.

script/generate migration AddAnniversaryToPerson anniversary:string
rake db:migrate


Then add the anniversary to our view.

#app/views/people/edit.html.erb
<h1>Editing person
<% form_for(@person) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :birthday %><br />
<%= f.date_select :birthday, :start_year=>1900 %>
</p>
<p>
<%= f.label :anniversary %><br />
<%= f.date_select :anniversary, :start_year=>1900 %>
</p>
<p>
<%= f.submit 'Update' %>
</p>
<% end %>

<%= link_to 'Show', @person %> |
<%= link_to 'Back', people_path %>




It looks like we're done so we click "Update" and .. Oops. It doesn't work! We get the error 1 error(s) on assignment of multiparameter attributes. Now we need to figure out what multiparameter attributes are and whey they're not working for us.


ActiveRecord::MultiparameterAssignmentErrors in PeopleController#update

1 error(s) on assignment of multiparameter attributes
RAILS_ROOT: /Users/alexrothenberg/date_select_example

Application Trace | Framework Trace | Full Trace
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:3061:in `execute_callstack_for_multiparameter_attributes'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:3022:in `assign_multiparameter_attributes'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:2749:in `attributes='
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:2627:in `update_attributes'
/Users/alexrothenberg/date_select_example/app/controllers/people_controller.rb:63:in `update'
...more stack trace...

Request

Parameters:

{"commit"=>"Update",
"_method"=>"put",
"authenticity_token"=>"qezkVq+MNzFuXxFBJ/GaSoh2BNdxM6oF3H7JP5beFFE=",
"id"=>"1",
"person"=>{"name"=>"Barack Obama",
"birthday(2i)"=>"8",
"birthday(3i)"=>"4",
"anniversary(1i)"=>"2009",
"anniversary(2i)"=>"5",
"anniversary(3i)"=>"22",
"birthday(1i)"=>"1960"}}


What happened? There are two keys to figuring out what's going on

  1. The date_select helper actually sends 3 http parameters to our application anniversary(1i), anniversary(2i) and anniversary(3i). ActiveRecord must combine those into a single Date before updating the row in the database.
  2. Looking at assign_multiparameter_attributes in active_record/base.rb we see this this comment that talks about combining 3 http parameters into a date type by calling new on the column type
    Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done by calling new on the column type or aggregation type (through composed_of) object with these parameters.
    So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum, f for Float, s for String, and a for Array. If all the values for a given attribute are empty, the attribute will be set to nil.



Now we know we're close to the right place and can check the column's return type using script/console


$ script/console
Loading development environment (Rails 2.3.2)
>> Person.columns_hash['birthday']
=> #
>> Person.columns_hash['birthday'].klass
=> Date

>> Person.columns_hash['anniversary']
=> #
>> Person.columns_hash['anniversary'].klass
=> String



This makes sense. ActiveRecord is treating the anniversary column as a string because that's what it is in the database so is not combining the 3 multiparameter attributes into a Date. What we need to do is override the default ActiveRecord logic and tell it to treat this column as a date. We can write a failing spec


require File.dirname(__FILE__) + '/../spec_helper'

describe Person do
it "should treat anniversary as a Date column" do
Person.columns_hash['anniversary'].klass.should == Date
end
end

# 'Person should treat anniversary as a Date column' FAILED
# expected: Date,
# got: String (using ==)


Then take advantage of a trick of Ruby that allows you to extend an object without affecting other instances of its class (see PickAxe book's explanation of this technique). If we lookup the definition of klass for a column It is actually very simple to implement our fix with the 5 lines below.


class Person < ActiveRecord::Base

class << columns_hash['anniversary']
def type
:date
end
end
end


Now our tests pass and when we go back to our site and click the Update button and it works.




How to use dates in Rails when your database stores a string

about 1 year ago | Alex Rothenberg: Common Sense Software

When working with Rails there's a lot of magic that happens behind the scenes to make it easy to do complex things. Most of the time you don't need to know how that "magic" works but there are times when things don't work as expected and its helpful to dig in and understand what Rails is doing under the covers so you can change how it works. Did I just say "change how Rails works"?!? I did! Rails is opinionated software that seeks to lead you down the golden path but there are legitimate times when you have to veer off that path and Rails lets you do so. I find this most often happens to me when I'm dealing with an existing legacy database which is not setup as Rails would like.

Today I'm going to go through an example that happened to me recently when I had an existing database that stored some dates in a text column but I needed to treat them as dates in my UI. I couldn't change the type of that column as there was another legacy application that expected it to be text.

Using Dates the Rails Way

First let's look at how easy it is to work with dates when you can follow the Rails Way. Let's create a new project and add a scaffolded Person object with a date attribute called birthday.


rails date_select_example
cd date_select_example
script/generate scaffold person name:string birthday:date
rake db:migrate


Now if we hit the site and try to create a new person we see a screen like this



And when you click "Create"



Exactly what you want with almost no code in the view and none in the model. I did make a minor edit to the view so we would get 1960 in the year select by adding :start_year=>1900 (a full documentation of date_select options are available here)


#app/views/people/new.html.erb
<h1>New person
<% form_for(@person) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :birthday %><br />
<%= f.date_select :birthday, :start_year=>1900 %>
</p>
<p>
<%= f.submit 'Create' %>
</p>
<% end %>

<%= link_to 'Back', people_path %>


and

#app/models/person.rb
class Person < ActiveRecord::Base
end


Errors when storing as text in the database

Now what happens when you run into a case where the date is stored as a string in the database. Let's say we have an "anniversary" attribute stored as a string that we want to treat the same way as we did birthday. We create the migration.

script/generate migration AddAnniversaryToPerson anniversary:string
rake db:migrate


Then add the anniversary to our view.

#app/views/people/edit.html.erb
<h1>Editing person
<% form_for(@person) do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :name %><br />
<%= f.text_field :name %>
</p>
<p>
<%= f.label :birthday %><br />
<%= f.date_select :birthday, :start_year=>1900 %>
</p>
<p>
<%= f.label :anniversary %><br />
<%= f.date_select :anniversary, :start_year=>1900 %>
</p>
<p>
<%= f.submit 'Update' %>
</p>
<% end %>

<%= link_to 'Show', @person %> |
<%= link_to 'Back', people_path %>




It looks like we're done so we click "Update" and .. Oops. It doesn't work! We get the error 1 error(s) on assignment of multiparameter attributes. Now we need to figure out what multiparameter attributes are and whey they're not working for us.


ActiveRecord::MultiparameterAssignmentErrors in PeopleController#update

1 error(s) on assignment of multiparameter attributes
RAILS_ROOT: /Users/alexrothenberg/date_select_example

Application Trace | Framework Trace | Full Trace
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:3061:in `execute_callstack_for_multiparameter_attributes'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:3022:in `assign_multiparameter_attributes'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:2749:in `attributes='
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:2627:in `update_attributes'
/Users/alexrothenberg/date_select_example/app/controllers/people_controller.rb:63:in `update'
...more stack trace...

Request

Parameters:

{"commit"=>"Update",
"_method"=>"put",
"authenticity_token"=>"qezkVq+MNzFuXxFBJ/GaSoh2BNdxM6oF3H7JP5beFFE=",
"id"=>"1",
"person"=>{"name"=>"Barack Obama",
"birthday(2i)"=>"8",
"birthday(3i)"=>"4",
"anniversary(1i)"=>"2009",
"anniversary(2i)"=>"5",
"anniversary(3i)"=>"22",
"birthday(1i)"=>"1960"}}


What happened? There are two keys to figuring out what's going on

  1. The date_select helper actually sends 3 http parameters to our application anniversary(1i), anniversary(2i) and anniversary(3i). ActiveRecord must combine those into a single Date before updating the row in the database.
  2. Looking at assign_multiparameter_attributes in active_record/base.rb we see this this comment that talks about combining 3 http parameters into a date type by calling new on the column type
    Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done by calling new on the column type or aggregation type (through composed_of) object with these parameters.
    So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum, f for Float, s for String, and a for Array. If all the values for a given attribute are empty, the attribute will be set to nil.



Now we know we're close to the right place and can check the column's return type using script/console


$ script/console
Loading development environment (Rails 2.3.2)
>> Person.columns_hash['birthday']
=> #
>> Person.columns_hash['birthday'].klass
=> Date

>> Person.columns_hash['anniversary']
=> #
>> Person.columns_hash['anniversary'].klass
=> String



This makes sense. ActiveRecord is treating the anniversary column as a string because that's what it is in the database so is not combining the 3 multiparameter attributes into a Date. What we need to do is override the default ActiveRecord logic and tell it to treat this column as a date. We can write a failing spec


require File.dirname(__FILE__) + '/../spec_helper'

describe Person do
it "should treat anniversary as a Date column" do
Person.columns_hash['anniversary'].klass.should == Date
end
end

# 'Person should treat anniversary as a Date column' FAILED
# expected: Date,
# got: String (using ==)


Then take advantage of a trick of Ruby that allows you to extend an object without affecting other instances of its class (see PickAxe book's explanation of this technique). If we lookup the definition of klass for a column It is actually very simple to implement our fix with the 5 lines below.


class Person < ActiveRecord::Base

class << columns_hash['anniversary']
def type
:date
end
end
end


Now our tests pass and when we go back to our site and click the Update button and it works.




Being pixel perfect - Part 8 (Standards anyone?)

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

Here's what we could to do to address the lack of discipline in front-end development:

1) Set a standard for front-end development
- create a template that development teams can use as a starting point
- it will include page layout and CSS

Next steps: James is creating the template

2) Validate compliance to the standard
If all our apps include the standard CSS then we can ensure that:
- every HTML element has a style specified in the markup (reset.css)
- the style specified in the markup is present in the CSS (default HTML elements + common styles. Overrides and app-specific styles will be in app's stylesheet)
- the CSS class is as per the standard (e.g. errors should be size: 8, color: red, font: arial)

Next steps: We're investigating ways to test for the standard CSS include in our continuous integration cycle

Being pixel perfect - Part 7 (Building front-end development skills)

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

We plan to do the following to address the gap in front-end development skills:

1) Raise the bar of front-end development skills in our engineering pool
- Set expectations for engineers: All engineers are expected to have a certain level of proficiency in front-end development
- Conduct hands-on training: Allan, who has front-end development experience, will conduct the class.

2) Develop front-end engineers
- Develop 2 - 4 front-end specialists who can champion front-end development standards, testing, coaching

Being pixel perfect - Part 6 (Why aren't we pixel perfect?)

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

Lets discuss why aren't we pixel perfect? I see two main reasons for this...

1) We lack front-end development skills
- Our engineers understand and practice Java/Ruby/SQL quite well but most don't know (and ever want to touch) the HTML/CSS code

2) We're not disciplined in creating user interfaces
- Our struggle in being pixel perfect includes page (HTML element) styling... We don't follow a standard to ensure consistent apps. It results in inconsistent rendition of pages in our apps - style (font, color, size) and behavior (link, forms, errors).

Parisian perfection, part two.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan


Hello, doves!

Just wanted to let you all know that the second half of my guest post for Jauntsetter is now up and blogged for your reading pleasure. Enjoy, and tune in shortly for a new edition of Queenie's Take!

Au revoir!

Who moved my cheese ?

about 1 year ago | Niranjan Sarade: InLoveWithNature

The book 'Who moved my cheese?' has been written by Spencer Johnson. It's an amazing way to deal with change in our work and in our life. Many people have reported that what they discovered in the story has improved their careers, businesses, health and marriages.

I found this book very interesting as it correctly identifies human thinking patterns.

Cheese is a metaphor for what you want to have in life - whether it is a good job, a loving relationship, etc.

Maze is where you look for what you want - the organisation you work in, or the family or community you live in.

There are four imaginary characters depicted in the story. They intend to represent the simple and complex parts of ourselves, regardless of our age, gender, race or nationality.

Sniff :- who sniffs out change early
Scurry :- who scurries into action
Hem :- who denies and resists change as he fears it will lead to something worse
Haw :- who learns to adapt in time when he sees changing can lead to something better !


Here are the simple but very important notes/principles mentioned in this book :-

(1) Having cheese makes you happy
(2) The more important your cheese is to you, the more you want to hold on to it
(3) If you do not change, you can become extinct
(4) What would you do if you weren't afraid ?
(5) Smell the cheese often so you know when it is getting old
(6) Movement in a new direction helps you find new cheese
(7) When you stop being afraid, you feel good !
(8) Imagining yourself enjoying your new cheese leads you to it
(9) The quicker you let go of old cheese, the sooner you find new cheese
(10)It is safer to search in the maze, than remain in a cheeseless situation
(11)Old beliefs do not lead you to new cheese
(12)When you see that you can find and enjoy new cheese, you change course
(13)Noticing small changes early helps you adapt to the bigger changes that are to come


Enjoy reading ! :-)

Getting closer to our business...

about 1 year ago | Biju Bhaskar: Thoughts on enterprise application development...

All of us agree that to become a successful Application development/IT organization, we need to get more closer to business...

Recently, we experimented with one of our folks from Application Development working with our business for 3 months. The insights she had into their business process, how our current products are helping/hindering the business, what are the gaps in our IT systems & support etc. were very valuable. In this case she worked in the business team as one of them. She did everything a business person would do for those 3 months.

This also gives an opportunity for IT to take some of our processes to add value to business. For example, she is planning to recommend to business to do Retrospectives at the end of their each peak business cycle. Probably IT can help facilitate the first time. Wouldn't that be great for any firm to have business and IT that closer? My dream is to have business adopt an agile/lean process like Scrum or Kanban for their day to day work.

Anyway, I think we should aggressively pursue more similar opportunities for our Business Analysts/Product Owners and others to work with business, and also have some business folks work in IT for a short duration (ideally 3 months time box). That way we would know first hand the current pains business have, and try to solve them. While doing that, business can learn some of the good IT practices as well...

Have you tried anything like this in your organization?

Getting closer to our business...

about 1 year ago | Biju Bhaskar: Thoughts on enterprise application development...

All of us agree that to become a successful Application development/IT organization, we need to get more closer to business...

Recently, we experimented with one of our folks from Application Development working with our business for 3 months. The insights she had into their business process, how our current products are helping/hindering the business, what are the gaps in our IT systems & support etc. were very valuable. In this case she worked in the business team as one of them. She did everything a business person would do for those 3 months.

This also gives an opportunity for IT to take some of our processes to add value to business. For example, she is planning to recommend to business to do Retrospectives at the end of their each peak business cycle. Probably IT can help facilitate the first time. Wouldn't that be great for any firm to have business and IT that closer? My dream is to have business adopt an agile/lean process like Scrum or Kanban for their day to day work.

Anyway, I think we should aggressively pursue more similar opportunities for our Business Analysts/Product Owners and others to work with business, and also have some business folks work in IT for a short duration (ideally 3 months time box). That way we would know first hand the current pains business have, and try to solve them. While doing that, business can learn some of the good IT practices as well...

Have you tried anything like this in your organization?

Strawberries have landed!

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

In other news, I love Twitter. Thanks for the update, @maggiejane!

Forgive me readers, for I have sinned.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

On Sunday, while my laundry tumbled in the dryer, I ran to the grocery store to buy some orzo for my lunches this week. After being horrified by the price of a box of De Cecco at my local Food Emporium, another kind of pasta caught my eye. Not until that moment had I realized what I wanted for dinner: Kraft macaroni and cheese from the box.

Reader, I bought that mac & cheese, and I ate it. Yes, I am a vehement advocate of all things seasonal and local, an evangelist for all things slow and unprocessed. However. I, too, have my American-grown food weaknesses, and that powdery, salty, orangey goodness is at the top of a very short list (which also includes chicken McNuggets and Friendly's Reeses Pieces sundae).

When I read the side of the box, I noticed that the recipe seems to have changed slightly since I last bought Kraft dinner. Instead of a tablespoon of butter, the recipe now calls for just half a tablespoon, and it specifies skim milk in lieu of whole. Interesting, no? I didn't have any milk in the house, so I subbed in water, which, frankly, works just as well.

I made a salad to eat alongside, to assuage my nutritional guilt, and dug into the bowl of bright orange, dinosaur-shaped noodles. Let me tell you, people - it was dang good. Better than Cheetos. Better than Hostess cupcakes. But while it was a fantastic trip down memory lane, it was not better than spaghetti carbonara. Phew.

Well, golly gee!

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

Jauntsetter is my latest addiction.

A most fabulous travel site and weekly newsletter for New York women, Jauntsetter highlights travel deals, tips and tricks for ladies traveling from the New York area. Each week, they feature a different destination (recent spots include Baltimore and Fire Island) and a different Jauntsetter of the Week. The Jauntsetters are always cool women with great travel wisdom to share, and I love hearing about their experiences, especially those related to food (um, duh).

Earlier this week, Jauntsetter editor Dororthy McGivney posted some musings on traveling solo, inspired by her (current!) trip to Paris. I tweeted her to let her know how much I loved the post, and we got to talking a bit about great things to do in Paris.

And then, the most exciting thing of all happened - Dorothy invited me to write a guest post and share my Parisian favorites with Jauntsetter's readers!

The first half of my perfect Parisian day is already posted over at Jauntsetter, with a second post (all about ice cream, Camille and wine) planned for this afternoon. Go check it out, and make sure to sign up for Jauntsetter's newsletter while you're at it!

Astronomical Dating of the Ramayan and South America was known in Ramayan era - by Dr. P V Vartak

about 1 year ago | Niranjan Sarade: InLoveWithNature

I recently read a book "Vastav Ramayan" (Real Ramayan) written by Dr. P.V.Vartak.
He has done scientific research and calculated dates of the important events during Ramayan era. It is a very interesting and scientific book that everyone should read.

Here is a link for Astronomical Dating of the Ramayan :-

Astronomical dating of Ramayan events

Also, his research shows that South America was known at the Ramayan era. Indians migrated to South America which is called "Patal Lok" in sanskrit. There are some places in South America which denote the Indian culture, like Surya Mandir (Sun Temple), Elephants, Lord Ganesha and snakes carved on ancient monuments, etc.

In Ramyan, when King Sugriv directs his men in all directions in search of Sita, he instructs people going to east direction to check out for a TRIDENT engraved on a mountain. He describes the Trident as "A long Golden flagstick with three limbs stuck on top. It always glitters in when seen from sky". (This trident is on west coast of peru - Lima and is visible clearly from the sky)

In Valmiki Ramayan - Kishkindha Kaand - The sanskrit shlok is as below: (Kishkindha-39/47-48)




The entire Valkimi Ramayan can be found at :-

Complete Valkimi Ramayan in Sanskrit

The description given is so clear that Sugriv or Sage Valmiki must have seen this trident from sky proving they might have aeroplanes to travel.



Around 100 miles from this trident, there is a place called Nazca or Nasca, where gigantic geometric shapes are drawn on land (Spread in miles across). These are visible from sky only. Looks like big airport at that time.

Pls visit these links so that you can get a picture.
Trident at Lima-Peru
Nazca lines

According to Dr. P. V. Vartak, the trident is a sign of east ( as we have 180 degrees today to decide from where west starts ). This was created by Lord Vishnu around 15000 - 17000 years ago. And the lines on the Nazca are the signs of Ancient Airport of King Bali, around 15000 years ago.

If you get a chance, please read this book - Vastav Ramayan! It is awesome !

Also the book 'PataalYatra' by Anil Patil is good to read. It is a fiction inspired by South America and Pataal invention by Dr. P V Vartak.

Michael Crichton's fictions

about 1 year ago | Niranjan Sarade: InLoveWithNature

I have read few fictions of Michael Crichton and very impressed with his writing skills. He keeps one totally engrossed with the story.

Jurassic Park, The Lost World, The Terminal Man, Eaters of the Dead, Timeline, State of Fear, The Andromeda Strain are some of his fictions that I have read and liked all of these.

I have also seen some movies that are based on his novels, but truely speaking the thrill that I experienced while reading the novels was much greater than watching the movie :-)

En plein air.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

You know it's almost summer in New York when you eat outside for the first time. This probably isn't so different for non-New Yorkers - when I was growing up in Connecticut, we used to eat outside as soon as it got warm enough - but there's a curious willingness on a New Yorker's part to brave the smog and noise of congested avenues to dine al fresco the second the thermometer passes 70 degrees. (My friend Miles is a notable exception to this rule.)

Last Friday, after spending an afternoon off from work baking my sunscreen-slathered self on a rock in Central Park (that's a shot of the Great Lawn, taken just before dinnertime), I met my friend Cristin for an early dinner at Bar Boulud, near Lincoln Center. We actually ate there together at about the same time last year - and this time around, we had basically the same meal. Except, this time, we got to eat outside and enjoy the sunshine.

We shared a few small things, which seems to me to be the best way to eat, the vast majority of the time. Cristin ordered a flight of red wines, I tucked into a flight of French whites (white Burgundy - is there arnything better?), and we shared escargot, pâté grand-mère, and some delectably crispy French fries. Bar Boulud wins many, many points for serving its fries with tangy, European-syle mayonnaise. MANY POINTS.

(They lose a few points for some pretty shoddy service, though. They were hovering and imposing for the first twenty minutes, and then, when we were ready to order, they disappeared. They forgot Cristin's second glass of wine, too. For shame, frankly, at the price of $17 a glass.)

But, aside from the service glitches, it was a great, warm, sunny meal. So what if it's back in the 50s today?

Getting ready.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

My regular readers know that I am growing more and more impatient for the arrival of summer's bounty to the Greenmarket. I'm craving berries and tomatoes and corn and peaches - and I can almost taste the strawberries, which are bound to show up any day now.

In preparation, I've been reading through last summer's issues of Gourmet. It hasn't helped allay my cravings - but it has reminded me of a couple of recipes I wanted to make last year and never got around to tackling. Among them are the Aussie burger, tomato and honeydew salad, grilled watermelon and tomato salad, and cheesecake with minted blackberries.

I also found a dessert I made last year that I want to make again this summer: mascarpone-filled cake with sherried berries. Oh yes. Come to Mama.

Photo of the mouthwatering cake is courtesy of Gourmet.com.

What are our biggest opportunities?

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

What is the next big opportunity for us move our application development team to the next level?

Where is that food truck? Check Twitter

about 1 year ago | Amy Grandov: Technology for Social Innovation

Despite all the hype about Twitter, I personally haven't found much practical need for it (though it may come to me yet...). So I was pleasantly surprised and amused to stumble on an article about food trucks that are using Twitter to let their customers know where they are. Finally, something useful and fun! One of the biggest drawbacks to food carts is you never know where to find them when you need them. When you're hungry, its a lot easier to stop at a local deli, even if you're really craving a WMD ("Wafle of Mass Deliciousness") from the Wafels and Dinges truck. With Twitter, the carts can inform their followers when and where to find them, and what's new on today's menu. This deceptively simple innovation can actually make a small business more competitive.

I'm not sure how this contributes to greater social good, other than bringing hungry people and good food together. But if I stretch a little, I can see how entrepreneurs with little investment capital can take advantage of cheap, widely available technologies like Twitter and mobile phones to compete for customers. And entrepreneurship is one of the most reliable tickets out of poverty in any country.

Being Pixel Perfect - What makes a great user interface?

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

Attention to detail!

Yes, we cannot be lazy about the user interface. Ignoring it affects overall quality. Our applications need to be polished! We must be proud of what we've produced.

Are you proud of your work?

97 things every software architect should know

about 1 year ago | Lalatendu Das: Interpretations of Technorealism

While browsing through my daily dose of RSS feeds on Google reader, I came across this interesting website, which talks of "97 Things every software architect should Know". Here are my top three picks (not in any specific order) out of the list of 97 'things' :-

1. Simplicity before generality, use before reuse :- Couldn't have agreed more. Having been a developer myself, I have seen developers often resorting to speculative design, under the guise of re-usability

2. Seek value in requested capabilities :- With apt examples the author, describes, how the role of a technical architect should be to help sponsor understand what they need. Ties back well to the agile manifesto

3. Pattern Pathology :- At times we assume design patterns to be the solution to all complex business problems. We enforce certain design patterns in project without checking if there are any simpler/ better solution available. The Author describes this symptom as 'Pattern Pathology' and makes a Strong case against it

Recommended reading for all..would like to know what are your picks..

Paperclip sample app part 2: downloading files through a controller

about 1 year ago | Pat Shaughnessy: Pat Shaughnessy - Home

Last time I wrote about how to quickly setup a Rails application using scaffolding that allows users to upload image files and then display them using the Paperclip plugin. Paperclip does the simplest thing possible by default: it saves the file attachments right on the file system of your web server, allowing you to download them to users easily using Apache or whatever web server you have installed.

Today I’d like to take that sample app one step further and show how to use a Rails controller to download the files, instead of directly through Apache. To get the finished code just go to http://github.com/patshaughnessy/paperclip-sample-app and look at the “part2” folder.

There are a variety of reasons why you might want to do this, including:

  • Security: you don’t want to expose all of the file attachments to all users of your web site. Instead, you want to implement some business rules and show some files to some users, but not to others.
  • Auditing/logging: you want to keep track of who is viewing which files, or how many times they are viewing them.
  • You want to hide the actual location of the files from users, and instead map the files to URLs in some other pattern or manner.
  • Or, you might want not want to store the files on your web server’s file system at all, but instead in a database table or somewhere else. In Part 3 of this series, I’ll show how to do this…

The common thread here is that you want to execute some Ruby code every time a users accesses a file, and the way to do that is by routing the download requests through a controller.

Let’s pick up where we left off last time:

If we take a look at some of the HTML source for this page:

<h1>Listing users</h1>
<table>
  <tr>
    <th>Photo</th>
    <th>Name</th>
    <th>Email</th>
  </tr>
<tr>
    <td><img alt="Mickey-mouse"
      src="/system/avatars/1/thumb/mickey-mouse.jpg?1242395876" /></td>
    <td>Mickey Mouse</td>
    <td>mickey@disney.com</td>
    <td><a href="/users/1">Show</a></td>
    <td><a href="/users/1/edit">Edit</a></td>

… we can see that Paperclip’s “url” function which we called in index.html.erb is returning a pointer to the actual location of the file on the web server’s hard drive, under the public/system folder:

$ find public/system
public/system
public/system/avatars
public/system/avatars/1
public/system/avatars/1/original
public/system/avatars/1/original/mickey-mouse.jpg
public/system/avatars/1/small
public/system/avatars/1/small/mickey-mouse.jpg
public/system/avatars/1/thumb
public/system/avatars/1/thumb/mickey-mouse.jpg

Now let’s say that we want to implement some simple security around these images…. reason #1 from my list above. The first thing we’ll need to do, then, is to remove the image files from the public folder and instead save them in some non-public place on our web server, for example:

$ mkdir non-public
$ mv public/system non-public/.

Now let’s double check that Apache can’t find the files in their new location:

Great! We see a missing image as expected. No users can see the files unless we run some bit of Ruby code to enable access. Now… how can we use a controller to download the files through Rails, instead of through Apache? The first thing we need to do is add a route to routes.rb for accessing the files.

If you open up routes.rb and look at what the scaffolding generator created for us, you’ll see this:

ActionController::Routing::Routes.draw do |map|
  map.resources :users
  ...etc...
  map.connect ':controller/:action/:id'
  map.connect ':controller/:action/:id.:format'
end

The map.resources line indicates that our application supports a series of routes that handle the four REST actions: GET, POST, PUT and DELETE. The best way to get a handle on how the routes work is by running “rake routes” to list out all the URL patterns that Rails will match on:

$ rake routes
(in /Users/pat/rails-apps/paperclip-sample-app)
    users GET    /users(.:format)          {:action=>"index", :controller=>"users"}
          POST   /users(.:format)          {:action=>"create", :controller=>"users"}
 new_user GET    /users/new(.:format)      {:action=>"new", :controller=>"users"}
edit_user GET    /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
     user GET    /users/:id(.:format)      {:action=>"show", :controller=>"users"}
          PUT    /users/:id(.:format)      {:action=>"update", :controller=>"users"}
          DELETE /users/:id(.:format)      {:action=>"destroy", :controller=>"users"}
                 /:controller/:action/:id           
                 /:controller/:action/:id(.:format)

The last two lines are the “default routes,” which connect any URL matching the pattern controller/action/id to the corresponding controller. We could just go ahead and use the default routes, but to learn a bit more about how map.resources works, let’s create a new URL pattern for our users that we’ll use in a minute to download the avatar file attachments with. Edit routes.rb and add the :member parameter in bold:

ActionController::Routing::Routes.draw do |map|
  map.resources :users, :member => { :avatars => :get }
etc...

If we now re-run rake routes, we can see that a new URL pattern was created for us that we can use to download the avatar images via a GET request:

$ rake routes
(in /Users/pat/rails-apps/paperclip-sample-app)
      users GET    /users(.:format)          {:action=>"index", :controller=>"users"}
            POST   /users(.:format)          {:action=>"create", :controller=>"users"}
   new_user GET    /users/new(.:format)      {:action=>"new", :controller=>"users"}
  edit_user GET    /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
avatars_user GET   /users/:id/avatars(.:format) {
                                              :action=>"avatars",
                                              :controller=>"users"
                                             }
       user GET    /users/:id(.:format)      {:action=>"show", :controller=>"users"}
            PUT    /users/:id(.:format)      {:action=>"update", :controller=>"users"}
            DELETE /users/:id(.:format)      {:action=>"destroy", :controller=>"users"}
                   /:controller/:action/:id           
                   /:controller/:action/:id(.:format)

Now to get the avatar for user 7, for example, we can issue a URL like this:

http://localhost:3000/users/7/avatars

… and the request will be routed to the “avatars” action in the “users” controller (plural since a user might have more than one style of avatar). So now let’s go right ahead and implement the avatars method and add some code to download a file to the client. The way to do that is to use ActionController::Streaming::send_file. It’s simple enough; we just need to pass the file’s path to send_file as well as the MIME content type which the client uses as a clue for deciding how to display the file, and that’s it! Let’s hard code these values for now and see if it all works (update the path here for your machine):

class UsersController < ApplicationController
  def avatars
    send_file '/path/to/non-public/system/avatars/1/original/mickey-mouse.jpg',
      :type => 'image/jpeg'
  end

Now if you type http://localhost:3000/users/1/avatars into your browser you should see the mickey image again. If not, then double check your code changes, where the files are actually located on the hard drive now and also try stopping and reloading the Rails app since changes to routes.rb are cached and are only loaded when Rails is initialized.

Instead of hard coding the path in the avatars method, we obviously need to be able to handle requests for any avatar file attachment for any user record. Before we enhance our code to do this, let’s take a few minutes to configure Paperclip and tell it where the files are now stored on the file system, and which URL we have configured our routes.rb file to use. This will make our work coding in the controller a lot easier, and also indicate to Paperclip where new file attachments should be uploaded to. To do this, we need to add a couple of parameters to our call to has_attached_file in our User model (user.rb), shown here in bold (again, update the path for your machine):

class User < ActiveRecord::Base
  has_attached_file :avatar,
    :styles => { :thumb => "75x75>", :small => "150x150>" },
    :path => '/path/to/non-public/system/avatars/1/original/mickey-mouse.jpg',
    :url => 'users/1/avatars'
end

Just to take one step at a time, I’ve hard coded the URL and path again here in the model. But now we can generalize our code in UserController to handle any user, like this:

def avatars
  user = User.find(params[:id])
  send_file user.avatar.path, :type => user.avatar_content_type
end

Now we can test http://localhost:3000/users/1/avatars again to be sure that we haven’t broken anything. If it’s all working, lets’ proceed to clean up the hard coding in user.rb. It turns out that Paperclip uses the same interpolations idea that we saw above in routes.rb. So I can use symbols like :rails_root, :id, :style, etc., and they will be evaluated to the values I expect and need. Here’s the finished code in my model:

has_attached_file :avatar,
  :styles => { :thumb => "75x75>", :small => "150x150>" },
  :path => 
    ':rails_root/non-public/system/:attachment/:id/:style/:basename.:extension',
  :url => '/:class/:id/:attachment'                    

If we open up the console and take a look at our user object there, we can see that Paperclip is substituting the correct values for each of the symbols I’ve provided:

$ ./script/console
Loading development environment (Rails 2.3.2)
>> User.first.avatar.url
=> "/users/1/avatars?1242395876"       (time stamp appended here automatically)
>> User.first.avatar.path
=> "/Users/pat/.../non-public/system/avatars/1/original/mickey-mouse.jpg"

Now let’s go back and test our original application again with our new code:

  • The new route in routes.rb
  • The new action in UserController
  • And the :url and :path parameters added to has_attached_file in the User model.

Oops… we see the large image again. It doesn’t work! What happened? Well, it turns our that we forgot one detail in our new avatars method in UserController. Our code always returns the default, or “original” style of the file attachment, but in the users index view we actually display the thumbnail image using image_tag user.avatar.url(:thumb). So our controller code needs to be able to handle requests for other styles as well. To do this, we need to pass the requested style somehow. The simplest thing to do is just to add the style as a URL parameter to the download request, like this:

  http://localhost:3000/users/1/avatar?style=thumb

(We could also add the style to the URL's path, but that would require another change to routes.rb.) To make this work, first I need to tell Paperclip about how I want to handle the style value in the URL:

has_attached_file :avatar,
  :styles => { :thumb => "75x75>", :small => "150x150>" },
  :path => 
    ':rails_root/non-public/system/:attachment/:id/:style/:basename.:extension',
  :url => '/:class/:id/avatar?style=:style'

And now I need to handle this new parameter in my controller:

def avatars
  user = User.find(params[:id])
  style = params[:style] ? params[:style] : 'original'
  send_file user.avatar.path(style),
            :type => user.avatar_content_type
end

I don’t need to change anything in index.html.erb since there we call image_tag user.avatar.url(:thumb) which picks up the new URL pattern from Paperclip.

And now, if I’ve got all of this correct, I should be able to finally see the thumbnail image again on the index page:

And finally we have files being downloaded by Ruby code present in the UserController class. If we actually wanted to implement security, logging or some other sort of logic we would just add code to the avatars method in UserController. For example, avatars could return a 401 (unauthorized) error if the user wasn’t logged in, or didn’t have access to view Mickey’s image for some reason.

That’s it for now; next time I’ll modify this sample app once more to demonstrate how we can store the image files in a database table, instead of in the “non-public” folder or anywhere on the file system.

Queenie's Take: Boston ahoy!

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

This week's Queenie's Take comes to you straight from Twitter, where I asked people to send their most pressing food and travel questions. So, today we'll be talking travel to Boston, and next week it'll be shopping & cafes here in NYC. Without further ado...

We're in Boston Sunday through Tuesday. What should we do? - Danielle (@foodmomiac)

Good question, Danielle! As a former denizen of New England, I have some Boston favorites to share with you - and since I know you have kids, I'm going to try to focus on stuff that you can all enjoy together!

Boston is one of those towns that brings out my nerdy side - American history, academia, great art - for such a small city, Boston has an incredibly rich cornucopia of stuff to tickle your brain. One of favorite museums is the Boston Museum of Science, with its awesome mid-century-version-of-the-future architecture and its Leonard Nimoy-narrated planetarium welcome. They also have a butterfly garden exhibition right now - something Dylan is bound to love.

My other favorite is the Museum of Fine Arts, which has an absolutely magnificent collection of John Singer Sargent's works (though we have my favorite - Madame X - here in NYC). He's one of my favorite artists, and seeing so many of his pieces together in one space is truly awe-inspiring.

For the adults, a wander down Beacon Hill's Charles Street might be in order. Filled to bursting with great shopping (clothes, home design, and the like) and good restaurants, it's just down the hill from the State House, and makes a nice afternoon walk. My cousin and her husband live up near the top of the hill, and I'm falling a bit more in love with the neighborhood on each visit.

Finally, for me, there was nothing cooler about my early trips to Boston than walking the Freedom Trail. Along the way you can choose to visit Paul Revere's house, Old North Church (in whose steeple hung the two lanterns signaling the approach of the British soldiers), and the USS Constitution. If your kids are anywhere near as geeky as I was (er, AM), they'll be psyched.

As far as food goes, you can't beat Boston for seafood, and for that, there are two spots I'd recommend. First, Barking Crab, downtown. Awesome lobster rolls, great fried clams, and great grilled fish, too. And, of course, there's the all-time classic, Summer Shack. Voted best lobster roll in Boston two years in a row, it's worth the trek out to Cambridge to visit the original location of Jasper White's seafood mecca. We ate here when my brother graduated from college, and I still think about it.

We expect a full report!

Photos courtesy of Pear_Biter, Shooothead, mkrigsman and Dan4th on Flickr.

Smartest Search Engine?

about 1 year ago | Erika Santos: Santos on Technology and Life

Wolfram Alpha is expected to be open to the general public sometime this month (some say as soon as this weekend). Good stuff. I can't wait to use it.

Being Pixel Perfect - Part 5 (How to test?)

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

In this post, lets address these questions, "How should we test?" and "Who should test?"...

Can we use a utility like Pixel Perfect so that designers and developers can test conformance to UI spec and claim being "done".

Pixel Perfect is a free Firefox* plugin (http://pixelperfectplugin.com)





* to test for pixel perfection in other browsers, we can use SmileDesignerSmile - a simple JavaScript (JQuery) implementation mimicking PixelPerfect

UI developer can use it to code & test as per the UI spec and UI designers can use it to verify compliance to UI spec.

It can test the entire page (if needed) or portions of the page and become the success criteria for UI development.

Thoughts?

Being Pixel Perfect - Part 4 (How to make it pixel perfect?)

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

Lets discuss "How should we make it pixel perfect?" and "Who should make it pixel perfect?" in this post.

Here's the flow I think of...

  1. The designer on the project creates the UI spec.

  2. The UI developer takes the UI spec and creates HTML rendition of the UI spec.

    - The HTML produced is the result of negotiations and agreements between the designer and the UI developer. Everything may not be possible and sometimes UI developer will have to modify the designs to be able to actually make it work in a web page. But the designer should always be aware of the changes the UI developer plans to make, and they should discuss to see what are the possibilities.

    - He/she can use free tools like Firebug (Firefox plugins) to edit/debug CSS/HTML live in the web page and compare their work to the UI spec using Pixel Perfect compare their to validate it

  3. The development team then takes the HTML code and builds the application using it. They don't have to worry about being pixel perfect as long as they don't change any "style" elements/code

So, it is the UI developer's responsibility to make the page components pixel perfect. With this process being pixel perfect can become much simpler.

Being Pixel Perfect - Part 3 (what to make pixel perfect?)

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

Lets discuss question #1 in this post... What should we make pixel perfect?

What is the unit of measure? How should we measure progress?

We should use page components as the unit of measure (not the entire page). The example of such page components include page header, footer, navigation etc.

  • A fully developed page with "real" content will often look different from the UI spec, which has mock-up content.
  • If a page component is reused across pages and isn't pixel perfect, then its better to track progress with "one component is not pixel perfect yet" rather than saying "two pages aren't pixel perfect yet" as work left is only on making one component pixel perfect
So lets start making page components pixel perfect. We can test page components to measure progress (# page components that are pixel perfect) and validate sites for pixel perfection [addressing "What should we test to be pixel perfect?"]

Being Pixel Perfect - Part 2

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

Some questions we need to address to make applications pixel perfect are:

  • What to make pixel perfect?
  • How to make it pixel perfect?
  • Who should make it pixel perfect?
  • What should we test to be pixel perfect?
  • How to test it?
  • Who should test it?
  • Why aren't we pixel perfect?

Being Pixel Perfect - Part 1

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

As developers we code for functionality/business rules/performance, and measure/test them to claim being "done" on a story.

We haven't yet put "conform to UI spec" in our done list (because it is hard to measure/test), which causes many issues like -

  • not being able to get a true sense of completeness/progress
  • designers complain that most front-end developers don’t seem to respect the designs when they build the templates. They just align stuff approximately, don’t notice all the details
This causes a big quality issue in our software that we (developers) don't notice/acknowledge.

I challenge us to add "conform to UI spec" in our done list to take our application quality to the next level.

I will post my thoughts and findings on how to achieve this in future posts...

Eat your greens.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan


I love lettuce and greens in all their various forms, but I will admit - I'm not great about using them at home. I tend to stick with romaine, which serves me for my meal-sized salads (a dinner eaten at least twice a week chez Queenie) as well as my smaller, side-salad creations.

Anything else I buy tends to sit in the fridge till it wilts enough to become completely unappealing. Such behavior is a waste of food and money, and so I've stopped pretending and mainly get my lettuce varietal fixes elsewhere.

That said, when I saw some fresh pea greens at the market last week, I couldn't pass them by. I love their sharp little bite and the crunch of the stems, and I thought they'd be the perfect thing alongside the duck leg I'd bought on the other side of the park. I did a little thinking, picked up a container of fresh fettuccine, and made my way back uptown.

When I got home, I chopped some shallot and a little garlic, seasoned and seared the duck leg (which I then popped in the oven to finish cooking), and sauteed half the pea shoots in a tiny bit of olive oil. I lined the pasta bowl with the other pea shoots (still raw), topped it with the fettucine and cooked greens, and placed the duck leg on top of it all. A shower of chives and a bit of salt and pepper later, lunch was ready!

Fresh Fettuccine with Pea Greens and Duck

1 duck leg, skin-side seasoned with salt and pepper
3 tsp. olive oil, separated
1 small shallot, minced
1 garlic clove, sliced
2 loosely-packed cups pea greens, separated
1 tbs. Dijon mustard
1 tsp. honey
2 tbs. dry white wine (or dry Vermouth)
1/4 cup finely chopped chives
1/4 lb. frsh fettucine, cooked according to package instructions
1/2 tbs. unsalted butter
Salt and pepper, to taste

Pre-heat the oven to 425 degrees Fahrenheit. In a small skillet set over high heat, heat 1 tsp. of the olive oil for a minute or two. Place the duck leg in the skillet, skin-side down, and let sear on high heat for a minute, then reduce heat to medium and continue to cook for three to four more minutes, until the skin is dark brown and crispy. Turn the leg over and transfer the skillet to the oven. Cook for 10 minutes, then remove from oven and let sit while you prepare the pasta.

In a medium skillet set over medium-high heat, saute the shallots in two teaspoons of the olive oil until transluscent, about one minute. Add the garlic and saute for a minute more. Add the pea greens and chives and saute for two minutes, or until wilted. Add the mustard & honey to the pan and stir into the greens, shallots and garlic, until both are evenly distributed. Cook for two minutes, then add the wine.

Stir briskly, making sure you get any good brown bits from the pottom of the skillet incorporated into the sauce, then turn the heat down until the pasta is ready. Once pasta is ready, drain (Do NOT rinse!) and add to the skillet. Turn the heat to medium and cook the pasta and sauce together for a few minutes, stirring to distribute the sauce throughout the pasta. Add the butter stir once or twice to incorporate, and turn off the heat.

Line your plate with the remaining pea greens, top with the pasta, and place the duck leg on top. Sprinkle the remaining chives over everything, season to taste, and eat!

Serves one, generously. I've made this recipe a few times this month, usually with fresh fettuccine. Last week, I used spaghetti - which works really well, too - so don't feel beholden to the fresh pasta rule!

Shaping Models in ruby on rails

about 1 year ago | Niranjan Sarade: InLoveWithNature

Whenever a new team member enters to any enhancement project, from technical perspective, he tries to understand the already developed code. Code comprehension may become difficult if there is no proper documentation. There can be many models with different relationships defined amongst themselves. Won't it be good to have some sort of diagrammatic representation of the Model relationships ? It will certainly be very helpful for the development and support teams to understand the application in technical perspective.

Let's develop small and simple ruby code to construct a diagrammatic representation
of the Model (Active Record) relationships (Model in M-V-C architecture) in any Ruby on Rails application. (We will follow KISS principle - Keep it simple and Succinct ! :-)

Active Record is an implementation of the object-relational mapping (ORM) pattern by the same name as described by Martin Fowler:

"An object that wraps a row in a database table or view, encapsulates
the database access, and adds domain logic on that data."



Active Record supports three types of relationship between tables:
(1) one-to-one
(2) one-to-many
(3) many-to-many.
You indicate these relationships by adding declarations to your models: has_one, has_many, belongs_to, and has_and_belongs_to_many.

There is a tool called 'Gvedit' (graphviz-2.20.2.exe) (http://www.graphviz.org/) which generates Directed and Undirected graphs. It accepts a dot file in specific format and it generates directed graphs free of cost ! :-) Why not use this tool ?

We can use the reflections for findling all associations of a Model.
http://api.rubyonrails.com/classes/ActiveRecord/Reflection/ClassMethods.html

Here is the utility which can be run from the rails application root and generates simple text file with the represention that the dot file requires for creating graphs. It looks for all the model classes under app/models directory.



It generates a simple text file as below :-

digraph model_relationship {
Asset -> DbFile [label=belongs_to]
Asset -> Thumbnail [label=has_many]
Category -> Child [label=has_many]
Category -> Content [label=has_and_belongs_to_many]
Category -> Parent [label=belongs_to]
Content -> Category [label=has_and_belongs_to_many]
Content -> Asset [label=belongs_to]
}


Save this as a .dot file. Open this file in Gvedit and run to generate the graph.

Here is a sample graph generated out of Gvedit :-



We can thus get a picture of all the model relationships in a typical ruby on rails application !

Tool Version Tracker rails application for sourceforge tools

about 1 year ago | Niranjan Sarade: InLoveWithNature

There are many sourceforge open source tools and it is sometimes difficult to track the latest vesions of all tools and keep us updated. We should atleast try to track the latest versions of the open source tools that we daily use in our projects.

So why not develop a very simple rails application which will allow you to add, edit and destroy tool information, the sourceforge url, version information, etc. Let's develop tool version tracker app with CRUD operations and some logic to track the tool versions :-) The logic may not be great but definitely useful for core developers who are always looking for new things/tools/versions ! Find the updated versions of the sourceforge tools and send an email with the updated versions to all team members :-) We can either run this periodically through web application or we can do some modifications to run this as a scheduled cron job :-)

We will use hpricot for parsing html.
Let's take an example of checkstyle. If we go to this link :- http://sourceforge.net/project/showfiles.php?group_id=29721

We will find the version information as :-


So in our code we will just compare the release number by parsing the html with hpricot and find out any change in version of the tool.

Here is the code in html_parser.rb under lib :-



In the environment.rb file, add the following line :-

SOURCEFORGE_URL = "http://sourceforge.net/project/showfiles.php?group_id="

For each tool, we have a unique group id.

The migration for Tool model is as below :-



You can view all the tools on index as below :-


You can find the updated version of individual tool or all tools by clicking on the links. So after clicking on the Update versions of all tools, you will get :-



And an email is also sent with the latest information (Simple Rails ActionMailer):-




You can edit/add the tool information from your application as :-


So how do you find it ? It is simple and easy to develop through Rails and definitely useful for all the Automated Tool Lovers :-)
It certainly solves our purpose :-)

Is User Centered Design too much of a good thing?

about 1 year ago | Amy Grandov: Technology for Social Innovation

Can putting people first be a bad thing? For User Centered Design (UCD) enthusiasts like myself, the UCD approach represents a movement towards making users the central focus of software design. It involves analyzing user needs and wants, and building an effective solution that is both appealing and easy to use. For me, technology is exciting precisely because of the possibilities it creates for people to work, connect, and solve problems in new and better ways.

In an article in the current issue of Interactions Magazine (published by ACM), Eric Schwikardt presents an interesting argument that UCD is inherently flawed and potentially dangerous. "Ethnographies, focus groups, cognitive modeling: Interaction design, at least, has become a process dedicated to catering to the user... It's almost a religion in our design schools, but it is in fact an incomplete philosophy that lacks a sense of responsibility for concerns other than those of the immediate end user."

He provides several examples of products (not limited to software) that are well designed from a user's perspective but have negative consequences in a larger context: SUVs that please drivers but damage the environment and put everyone else on the road at risk; kitchen gadgets that are cool and easy to operate but use no recycled materials; printer default settings for single sided copies and high resolution that waste paper and ink.

I'm still a fan of UCD, but there is a risk that should be acknowledged: In delivering the best possible "user experience" for your product, it doesn't automatically follow that you are you are maximizing the product's value for the whole community. For a consumer product, the larger community may be all of society, even the planet. In the more humble case of enterprise software, the community may secondary stakeholders who are impacted by the software but aren't direct users of it.

Security is a good example. Security requirements can degrade usability, but they are necessary to protect the organization. Another example involves common standards for user interfaces, technical architecture, etc. The standards may not be ideal for a particular set of users, but following established standards provides other benefits beyond the traditional scope of UCD.

In an enterprise, these stakeholders typically have a strong voice and influence over the outcome of a software project, so the risk of excessive attention to UCD doesn't seem as urgent. However, its a valuable exercise to look beyond the immediate end users of a software solution to examine the needs of other hidden stakeholders, and to choose your success metrics thoughtfully.

Flowers, flowers, everywhere!

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

I've gone a little poladroid-crazy lately, but, when there are so many gorgeous flowers to look at - can you blame me? Lilacs have been bountiful at the market for weeks now, and last Saturday brought the first of my absolute favorite - peonies - as well as some sweet little buttercups.

Happy spring!




Not the hard stuff, but it'll do for now.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan


For my money, asparagus rival ramps for the altogether-made-up title, "Spring's Greatest, Most Delicious Vegetable." Gloriously grassy (which makes sense, since asparagus is a grass, of sorts), asparagus is a perfect foil for many of spring's other goodies, such as farm-fresh eggs, chives - though it's no stranger to the more wintry parmesan and balsamic vinegar.

Over the last two weeks, I've made my way through four bunches of asparagus - some roasted, encrusted with grated parmesan, some blanched and dipped in homemade mayonnaise, some steamed and topped with an improvised, raw hollandaise (really just homemade mayo with extra lemon juice and chopped chives).

My cravings for strawberries, tomatoes and corn haven't abated, but the asparagus binge is helping to alleviate the pangs - for now.

Don't start a webapp with Javascript/AJAX-based designs

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

I'm not against the use of Javascript in web apps. However, we need to reinforce the mantra of "not starting with Javascript/AJAX-based designs" while designing a new web app.

  • It can help ensure graceful degradation for which basic HTML forms are needed anyway and starting with them ensures simple, straight forward app is built first to highlight any issues etc.
  • It also keeps things relatively simple...
Does the following order make sense to write a new web app?

HTML (content) -> CSS (style) -> Javascript (behavior/interactivity)

In a pickle.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan


My love for pickles is famous, in certain circles. When I was growing up in Connecticut, we'd pile in the car for drives up to my aunt and uncle's house in Massachusetts. The best part of the drive (aside from the destination, of course) was our regular pit stop at Rein's Deli just south of Hartford, where the sandwiches are massive, and the pickles just keep coming.

My love for pickling is a more recent development, but is no less of an obsession. When spring rolls around, I find myself desperate to pickle everything in sight, the better to preserve the bounty of the season through the long, cold winter I know is coming. Well, that - and I just love the sweet, vinegary crunch of a good pickle.

For the last few weeks, the greenmarket vegetable most worth pickling has been that stinky harbinger of spring: ramps. I follow this recipe from Serious Eats for my ramp pickling, and it hasn't steered me wrong yet. The fennel and coriander lend the ramps an additional complexity, enhancing their essential garlic-tinged, meaty flavor.

Pickling is super-easy, too - I don't have the storage space to do actual canning, so I just store my jars in the fridge till I have the opportunity to use the goodies I've accumulated. (Need some ideas about what to do with your bounty? Check out this link.) They also make fabulous gifts, and a couple of the jars I have in the fridge right now are slated to make their way into some hot little hands in the next couple of weeks. Lucky ducks.

Beautiful

about 1 year ago | Surbhi Bhati: Clean Desk, Jammed drawers

Deep in my heart it pains..
nothing like joy remains..
all I feel is ultimate despair,
tearful eyes are occasional if not rare..

I tried everything to make it work,
they laughed at me and said I was a jerk,
even to think that my efforts would succeed,
I was only as good as a second lead...

looks like mine don't catch the eye,
I do not register, any more than a passer by,
so what if my heart is of gold,
so what if its filled to the rim, with love for him many fold..

and just when I was sulking and sinking so low,
i saw him coming, his face aglow,
the passionate gleam in his eyes, that I always searched,
stopped right in my front why? I wondered..

he was talking to me, I couldn't believe,
I am always in his thoughts and do not leave,
the sparkle of my eyes, is what he can't forget,
if he wont say it now, he will always regret..

I am a person of substance,
its what he liked,
he said i was BEAUTIFUL,
and just then..i BEAUTIFIED....

Up close and personal, the full arsenal.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan


I think I've exhausted my trip to Stone Barns in terms of blogging material, but there's still more to see, if you're game.

So, if you're feeling the need to look at a few more pictures of adorable lambs, or to see the cows lazing about in their gorgeous pasture, have a gander at the full set of photos, right here. And enjoy!

Up close and personal, part three.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

The greenhouses at Stone Barns sit at the foot of a hill, spreading out below the titular stone barns and outbuildings, fanning down toward the bluffs that line the banks of the Hudson. In a landscape dominated by natural materials, flora and fauna, their glass, plastic and steel silhouettes seem a bit out of place, an invading force overtaking a rural idyll.

That is, of course, until you venture inside.

Filled with lettuce, carrots, seedlings, and two rabbits, the greenhouses are row after row of fun - walking along the neatly-spaced plantings, you find greens you never even knew existed, and, in Cristin's case, see your first ever still-in-the-ground carrot.

Deer tongue lettuce is in abundance, as is a rainbow of chard. Among the seedlings, we saw arugula, oregano, and thyme - labeled "Summa Thyme," for your chuckling enjoyment. As someone who has only recently begun to grow her own herbs (and one persnickety Meyer lemon tree), the sheer plenty of it all was fantastically inspiring. Yet another reason for my first home purchase to be a place upstate, where I can renovate, garden and entertain to my heart's content.

And, yes, of course you're all invited.

Up close and personal, part two.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

During our visit to Stone Barns, Cristin and I managed to cover a lot of ground. Walking to and fro across a hilly farm helps you work up an appetite, so after a visit to the lambs, ducks, geese, pigs and greenhouses, we headed to the (very, very crowded) cafe for some lunch.

After a good fifteen minutes in line (which gave us lots of time to browse the preserves, baked goods and for me to pick out my new, giant coffee mug), we made it up to the counter. We ordered salads (parsnip and beet), sandwiches (beet and bologna) and dessert (macarons) and headed for a picnic table outside.

We settled down in the shade to enjoy our booty. For me, an open-faced sandwich made with house-made bologna, pickled vegetables, and a generous slice of house-baked focaccia. The bread was spread with a rich, grainy mustard, which, together with the pickled cauliflower and carrots, contrasted gorgeously with the rich, meaty meat and the buttery bread.

On the side, I had a little of the beet salad (dressed with dill), and we both tried the cold curried parsnips - Cristin liked those more than I did, but I have to admit they were really, really interesting. Sweet and cool, but not crunchy - toothy, you might call them.

Cristin's sandwich was a winner - the same focaccia, topped with creamy goat cheese, thinly sliced beets, sauteed ramps, and a lemon vinaigrette. Stinky and pungent, thanks to the ramps, and sweet and cool, thanks to the beets. All in all, a major, major win.

For dessert, we each tried two macarons: one raspberry with chocolate filling, and one parsnip. The raspberry was a bit too sweet for either of us, and the parsnip was just kind of...there. The macarons themselves were really well done, with the perfect chewy-crunchy texture, and a beautiful sheen on them. Maybe I've just been too spoiled by Bouchon's masterpieces?

All in all, a pretty fantastic lunch. And my new coffee mug? It holds the equivalent of two normal cups of coffee, which of course means I love it. All hail the gods of caffeine!

Enabling cross-team learning - Part 2

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck


In the last post on enabling cross-team learning we discussed the reasons for limited cross-team learning. In this post, lets discuss ideas to solve for (3) no one is aware of all discussions* happening in our group.

We have an opportunity to significantly reduce the barrier for cross-team learning by solving for (3) in the short-term, by compiling the schedule of all team discussions in one central place.

We could do this simply by using a team/group calendar (we use Notes team rooms). All the teams would need to do is cc: this group calendar in their discussion invitations. And the end result will be a compilation of all schedules in the group calendar, which all of us can see to chose the relevant discussions to join...

Thoughts?

Enabling cross-team learning - Part 1

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

There is limited cross-team learning in our teams today. In a recent townhall, we discussed the reasons for this and the common themes were -

(1) Time: busy with our own projects
(2) Interest: limited value perceived in cross-team learning
(3) Transparency: no one is aware of all discussions* happening in our group

* CoE/initiatives/interest groups, townhalls, sprint/release planning/reviews/retrospectives etc.

We can solve this problem by working on the themes identified above in the reverse order 3 -> 2 -> 1, i.e. (3) help everyone get visibility into all team discussions, and then, (2) showcase some learning/value from cross-team learning and (1) team members will create time for cross-team learning.

I plan to try this out and will keep you posted.

Testing AJAX without a browser with Cucumber and Webrat

about 1 year ago | Alex Rothenberg: Common Sense Software

I have lately fallen in love with using Cucumber and Webrat for my integration/acceptance testing. Cucumber because it allows non-technical people to write or at least read the test scenarios and Webrat because it matches content and encourages you to write integration tests without relying on xpath to find html elements. The way I like to use these tools is to run Rails integration tests which means its fast since I don’t need to start a mongrel or fire up a browser and can use Rails’ transactional fixtures to rollback all my database changes at the end of each test scenario. The only downside is that you can’t test javascript.

Today I am going to talk about how to get around this and test a form with an ajax autocomplete field. I've built a sample application with all the code examples here and you can download it from http://github.com/alexrothenberg/testing-ajax-example if you like. The application I'm building is just some simple app created with scaffolding that just has a User resource with a name and address. I modified the /users page to not display all users but include the auto_complete typeahead to let you pick a user (imagining there may be a lot) so the page looks something like this.



My first test scenario will ignore the ajax and just test the form which is super easy and can be done by writing a single feature file.


#features/find_a_user.feature
Feature: Allow anyone to find a user and see their details
In order to handle a large set of users
I want search with autocomplete

Scenario: View a candidate detail page without testing ajax
Given "Mickey Mouse" is a user living at "123 Main Street"
When I am on the homepage
And I fill in "Which user" with "Mickey Mouse"
And I press "Find"
Then I should see "Mickey Mouse"
And I should see "123 Main Street"


I run it it all passes and I get


$ rake features
(in /Users/alexrothenberg/ruby/testing-ajax-example)
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I "/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/lib:lib" "/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/bin/cucumber" --format pretty --require features/step_definitions/user_steps.rb --require features/step_definitions/webrat_steps.rb --require features/support/env.rb --require features/support/paths.rb features/find_a_user.feature
Feature: Allow anyone to find a user and see their details
In order to handle a large set of users
I want search with autocomplete

Scenario: View a candidate detail page without testing ajax # features/find_a_user.feature:5
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I fill in "Which user" with "Mickey Mouse" # features/step_definitions/webrat_steps.rb:22
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

1 scenario (1 passed)
6 steps (6 passed)


I makes use of the default webrat steps that cucumber gives you for free in features/steps/webrat_steps.rb so I don’t even have to write any code to get it to pass but I still haven’t tested any of my code that responds to the autocomplete request. I’d like my test to verify that my routes, controller and model will all work together. So, I write another scenario and run it and this time it fails because I haven't defined the typeahead steps for the typeahead lines.


<first scenario omitted>

Scenario: View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I typeahead in "Which user" with "Mickey Mouse" # features/find_a_user.feature:16
And I fill in "Which candidate" with the first typeahead result # features/find_a_user.feature:17
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

2 scenarios (1 undefined, 1 passed)
13 steps (3 skipped, 2 undefined, 8 passed)

You can implement step definitions for undefined steps with these snippets:

When /^I typeahead in "([^\"]*)" with "([^\"]*)"$/ do |arg1, arg2|
pending
end

When /^I fill in "([^\"]*)" with the first typeahead result$/ do |arg1|
pending
end


Now I take the hints cucumber has given me and write my autocomplete steps. The interesting thing here is that I need to leave the response object unchanged so I can fill in the form field after running the typeahead step so I can't use the existing webrat steps as they work on a single pair of request and response objects. So I knew I'd be creating a new class with its own request and response that could be used without affecting the one used by my other cucumber steps. Using good outside-in development practices I deferred thinking about how to do that and first wrote my steps file to look something like this. One interesting thing to notice here is that you can invoke a step from inside another step just by omitting the block as I do in the second step.


When /^I typeahead in "(.*)" with "(.*)"$/ do |field, value|
field = field_labeled field
@typeahead = AutoCompleteStepHelper.new(request)
@typeahead.type(field, value)
end

When /^I fill in "(.*)" with the first typeahead result$/ do |field|
When %Q[I fill in "#{field}" with "#{@typeahead.items.first}"]
end


Now when run the feature again it fails telling me I haven’t yet built the AutoCompleteStepHelper.


<first scenario omitted>

Scenario: View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I typeahead in "Which user" with "Mickey Mouse" # features/step_definitions/autocomplete_steps.rb:1
uninitialized constant AutoCompleteStepHelper (NameError)
./features/step_definitions/autocomplete_steps.rb:3:in `/^I typeahead in "(.*)" with "(.*)"$/'
features/find_a_user.feature:16:in `And I typeahead in "Which user" with "Mickey Mouse"'
And I fill in "Which candidate" with the first typeahead result # features/step_definitions/autocomplete_steps.rb:7
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

2 scenarios (1 failed, 1 passed)
13 steps (1 failed, 4 skipped, 8 passed)


So the next step is to write the AutoCompleteStepHelper class. This class’ job is to have its own request and response that will not affect the ones used by cucumber for the main page requests. It turns out that I can do this by having my class extend ActionController::IntegrationTest and I can even use webrat methods in it because webrat adds its methods to IntegrationTest. In this example I'm calling visit and current_dom and using nokogiri to parse the dom. It is a little weird that I'm subclassing IntegrationTest but this class is not a TestUnit class itself but I decided that was okay.


class AutoCompleteStepsHelper < ActionController::IntegrationTest
def initialize(existing_request)
@controller_name = existing_request.parameters[:controller]
@controller_class = "#{@controller_name.to_s.camelize}Controller".constantize
raise "Can't determine controller class for #{@controller_class_name}" if @controller_class.nil?

@controller = @controller_class.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@response.session = @request.session
end

def type(field, value)
visit url_for(:controller=>@controller_name, :action=>"auto_complete_for_#{field.id}", field.send(:name)=>value)
end

def items
current_dom.search('//ul/li').map(&:inner_html)
end
end


Now when I run the feature it all passes.


<first scenario omitted>

Scenario: View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I typeahead in "Which user" with "Mickey Mouse" # features/step_definitions/autocomplete_steps.rb:1
And I fill in "Which user" with the first typeahead result # features/step_definitions/autocomplete_steps.rb:7
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

2 scenarios (2 passed)
13 steps (13 passed)


The last step I took was to test that the list returned in the typeahead was correct. I created another scenario in my feature.


Scenario: Typeahead should return 2 users that match but not a third
Given "Mickey Mouse" is a user living at "123 Main Street"
And "Donald Duck" is a user living at "123 Pond Lane"
And "Minnie Mouse" is a user living at "123 Disney Avenue"
When I am on the homepage
And I typeahead in "Which user" with "Mi"
Then I should see in my typeahead "Mickey Mouse"
And I should see in my typeahead "Minnie Mouse"
And I should not see in my typeahead "Donald Duck"


and I added two new steps


Then /^I should see in my typeahead "(.*)"$/ do |text|
@typeahead.response_body.should =~ /#{text}/m
end

Then /^I should not see in my typeahead "(.*)"$/ do |text|
@typeahead.response_body.should_not =~ /#{text}/m
end


Now when I run my features all 3 scenarios are passing


$ rake features
(in /Users/alexrothenberg/ruby/testing-ajax-example)
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I "/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/lib:lib" "/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/bin/cucumber" --format pretty --require features/step_definitions/autocomplete_steps.rb --require features/step_definitions/user_steps.rb --require features/step_definitions/webrat_steps.rb --require features/support/autocomplete_steps_helper.rb --require features/support/env.rb --require features/support/paths.rb features/find_a_user.feature
Feature: Allow anyone to find a user and see their details
In order to handle a large set of users
I want search with autocomplete

Scenario: View a candidate detail page without testing ajax # features/find_a_user.feature:5
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I fill in "Which user" with "Mickey Mouse" # features/step_definitions/webrat_steps.rb:22
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

Scenario: View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I typeahead in "Which user" with "Mickey Mouse" # features/step_definitions/autocomplete_steps.rb:1
And I fill in "Which user" with the first typeahead result # features/step_definitions/autocomplete_steps.rb:7
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

Scenario: Typeahead should return 2 users that match but not a third # features/find_a_user.feature:22
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
And "Donald Duck" is a user living at "123 Pond Lane" # features/step_definitions/user_steps.rb:1
And "Minnie Mouse" is a user living at "123 Disney Avenue" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I typeahead in "Which user" with "Mi" # features/step_definitions/autocomplete_steps.rb:1
Then I should see in my typeahead "Mickey Mouse" # features/step_definitions/autocomplete_steps.rb:16
And I should see in my typeahead "Minnie Mouse" # features/step_definitions/autocomplete_steps.rb:16
And I should not see in my typeahead "Donald Duck" # features/step_definitions/autocomplete_steps.rb:20

3 scenarios (3 passed)
21 steps (21 passed)


What I've done is not full javascript testing (for that I'm planning to look into Blue-Ridge from Relevance). This technique does allow you to test ajax (skipping the "J") without a browser.

Testing AJAX without a browser with Cucumber and Webrat

about 1 year ago | Alex Rothenberg: Common Sense Software

I have lately fallen in love with using Cucumber and Webrat for my integration/acceptance testing. Cucumber because it allows non-technical people to write or at least read the test scenarios and Webrat because it matches content and encourages you to write integration tests without relying on xpath to find html elements. The way I like to use these tools is to run Rails integration tests which means its fast since I don’t need to start a mongrel or fire up a browser and can use Rails’ transactional fixtures to rollback all my database changes at the end of each test scenario. The only downside is that you can’t test javascript.

Today I am going to talk about how to get around this and test a form with an ajax autocomplete field. I've built a sample application with all the code examples here and you can download it from http://github.com/alexrothenberg/testing-ajax-example if you like. The application I'm building is just some simple app created with scaffolding that just has a User resource with a name and address. I modified the /users page to not display all users but include the auto_complete typeahead to let you pick a user (imagining there may be a lot) so the page looks something like this.



My first test scenario will ignore the ajax and just test the form which is super easy and can be done by writing a single feature file.


#features/find_a_user.feature
Feature: Allow anyone to find a user and see their details
In order to handle a large set of users
I want search with autocomplete

Scenario: View a candidate detail page without testing ajax
Given "Mickey Mouse" is a user living at "123 Main Street"
When I am on the homepage
And I fill in "Which user" with "Mickey Mouse"
And I press "Find"
Then I should see "Mickey Mouse"
And I should see "123 Main Street"


I run it it all passes and I get


$ rake features
(in /Users/alexrothenberg/ruby/testing-ajax-example)
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I "/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/lib:lib" "/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/bin/cucumber" --format pretty --require features/step_definitions/user_steps.rb --require features/step_definitions/webrat_steps.rb --require features/support/env.rb --require features/support/paths.rb features/find_a_user.feature
Feature: Allow anyone to find a user and see their details
In order to handle a large set of users
I want search with autocomplete

Scenario: View a candidate detail page without testing ajax # features/find_a_user.feature:5
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I fill in "Which user" with "Mickey Mouse" # features/step_definitions/webrat_steps.rb:22
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

1 scenario (1 passed)
6 steps (6 passed)


I makes use of the default webrat steps that cucumber gives you for free in features/steps/webrat_steps.rb so I don’t even have to write any code to get it to pass but I still haven’t tested any of my code that responds to the autocomplete request. I’d like my test to verify that my routes, controller and model will all work together. So, I write another scenario and run it and this time it fails because I haven't defined the typeahead steps for the typeahead lines.


<first scenario omitted>

Scenario: View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I typeahead in "Which user" with "Mickey Mouse" # features/find_a_user.feature:16
And I fill in "Which candidate" with the first typeahead result # features/find_a_user.feature:17
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

2 scenarios (1 undefined, 1 passed)
13 steps (3 skipped, 2 undefined, 8 passed)

You can implement step definitions for undefined steps with these snippets:

When /^I typeahead in "([^\"]*)" with "([^\"]*)"$/ do |arg1, arg2|
pending
end

When /^I fill in "([^\"]*)" with the first typeahead result$/ do |arg1|
pending
end


Now I take the hints cucumber has given me and write my autocomplete steps. The interesting thing here is that I need to leave the response object unchanged so I can fill in the form field after running the typeahead step so I can't use the existing webrat steps as they work on a single pair of request and response objects. So I knew I'd be creating a new class with its own request and response that could be used without affecting the one used by my other cucumber steps. Using good outside-in development practices I deferred thinking about how to do that and first wrote my steps file to look something like this. One interesting thing to notice here is that you can invoke a step from inside another step just by omitting the block as I do in the second step.


When /^I typeahead in "(.*)" with "(.*)"$/ do |field, value|
field = field_labeled field
@typeahead = AutoCompleteStepHelper.new(request)
@typeahead.type(field, value)
end

When /^I fill in "(.*)" with the first typeahead result$/ do |field|
When %Q[I fill in "#{field}" with "#{@typeahead.items.first}"]
end


Now when run the feature again it fails telling me I haven’t yet built the AutoCompleteStepHelper.


<first scenario omitted>

Scenario: View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I typeahead in "Which user" with "Mickey Mouse" # features/step_definitions/autocomplete_steps.rb:1
uninitialized constant AutoCompleteStepHelper (NameError)
./features/step_definitions/autocomplete_steps.rb:3:in `/^I typeahead in "(.*)" with "(.*)"$/'
features/find_a_user.feature:16:in `And I typeahead in "Which user" with "Mickey Mouse"'
And I fill in "Which candidate" with the first typeahead result # features/step_definitions/autocomplete_steps.rb:7
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

2 scenarios (1 failed, 1 passed)
13 steps (1 failed, 4 skipped, 8 passed)


So the next step is to write the AutoCompleteStepHelper class. This class’ job is to have its own request and response that will not affect the ones used by cucumber for the main page requests. It turns out that I can do this by having my class extend ActionController::IntegrationTest and I can even use webrat methods in it because webrat adds its methods to IntegrationTest. In this example I'm calling visit and current_dom and using nokogiri to parse the dom. It is a little weird that I'm subclassing IntegrationTest but this class is not a TestUnit class itself but I decided that was okay.


class AutoCompleteStepsHelper < ActionController::IntegrationTest
def initialize(existing_request)
@controller_name = existing_request.parameters[:controller]
@controller_class = "#{@controller_name.to_s.camelize}Controller".constantize
raise "Can't determine controller class for #{@controller_class_name}" if @controller_class.nil?

@controller = @controller_class.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@response.session = @request.session
end

def type(field, value)
visit url_for(:controller=>@controller_name, :action=>"auto_complete_for_#{field.id}", field.send(:name)=>value)
end

def items
current_dom.search('//ul/li').map(&:inner_html)
end
end


Now when I run the feature it all passes.


<first scenario omitted>

Scenario: View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I typeahead in "Which user" with "Mickey Mouse" # features/step_definitions/autocomplete_steps.rb:1
And I fill in "Which user" with the first typeahead result # features/step_definitions/autocomplete_steps.rb:7
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

2 scenarios (2 passed)
13 steps (13 passed)


The last step I took was to test that the list returned in the typeahead was correct. I created another scenario in my feature.


Scenario: Typeahead should return 2 users that match but not a third
Given "Mickey Mouse" is a user living at "123 Main Street"
And "Donald Duck" is a user living at "123 Pond Lane"
And "Minnie Mouse" is a user living at "123 Disney Avenue"
When I am on the homepage
And I typeahead in "Which user" with "Mi"
Then I should see in my typeahead "Mickey Mouse"
And I should see in my typeahead "Minnie Mouse"
And I should not see in my typeahead "Donald Duck"


and I added two new steps


Then /^I should see in my typeahead "(.*)"$/ do |text|
@typeahead.response_body.should =~ /#{text}/m
end

Then /^I should not see in my typeahead "(.*)"$/ do |text|
@typeahead.response_body.should_not =~ /#{text}/m
end


Now when I run my features all 3 scenarios are passing


$ rake features
(in /Users/alexrothenberg/ruby/testing-ajax-example)
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I "/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/lib:lib" "/Library/Ruby/Gems/1.8/gems/cucumber-0.3.2/bin/cucumber" --format pretty --require features/step_definitions/autocomplete_steps.rb --require features/step_definitions/user_steps.rb --require features/step_definitions/webrat_steps.rb --require features/support/autocomplete_steps_helper.rb --require features/support/env.rb --require features/support/paths.rb features/find_a_user.feature
Feature: Allow anyone to find a user and see their details
In order to handle a large set of users
I want search with autocomplete

Scenario: View a candidate detail page without testing ajax # features/find_a_user.feature:5
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I fill in "Which user" with "Mickey Mouse" # features/step_definitions/webrat_steps.rb:22
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

Scenario: View a candidate detail page testing (most of) the ajax # features/find_a_user.feature:13
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I typeahead in "Which user" with "Mickey Mouse" # features/step_definitions/autocomplete_steps.rb:1
And I fill in "Which user" with the first typeahead result # features/step_definitions/autocomplete_steps.rb:7
And I press "Find" # features/step_definitions/webrat_steps.rb:14
Then I should see "Mickey Mouse" # features/step_definitions/webrat_steps.rb:93
And I should see "123 Main Street" # features/step_definitions/webrat_steps.rb:93

Scenario: Typeahead should return 2 users that match but not a third # features/find_a_user.feature:22
Given "Mickey Mouse" is a user living at "123 Main Street" # features/step_definitions/user_steps.rb:1
And "Donald Duck" is a user living at "123 Pond Lane" # features/step_definitions/user_steps.rb:1
And "Minnie Mouse" is a user living at "123 Disney Avenue" # features/step_definitions/user_steps.rb:1
When I am on the homepage # features/step_definitions/webrat_steps.rb:6
And I typeahead in "Which user" with "Mi" # features/step_definitions/autocomplete_steps.rb:1
Then I should see in my typeahead "Mickey Mouse" # features/step_definitions/autocomplete_steps.rb:16
And I should see in my typeahead "Minnie Mouse" # features/step_definitions/autocomplete_steps.rb:16
And I should not see in my typeahead "Donald Duck" # features/step_definitions/autocomplete_steps.rb:20

3 scenarios (3 passed)
21 steps (21 passed)


What I've done is not full javascript testing (for that I'm planning to look into Blue-Ridge from Relevance). This technique does allow you to test ajax (skipping the "J") without a browser.

Social Network Analyser from SAP

about 1 year ago | Bhargav Gandhi: AGILE SOFTWARE DEVELOPMENT

I was browsing the Business Objects contents on SAP Community Network and came across a cool prototype that SAP is building. It is called as Social Network Analyser Prototype.


The good thing here is that it uses the enterprise data to build a social networking place. It helps by making the corporate relationships quickly visible/available and provides information about your colleagues.

SAP says - 
The purpose of this technology is to deliver an environment where people can easily and quickly analyze corporate network relationships and find the information they are looking for in their daily jobs. The social network analyzer prototype lets you import and aggregate all the business network relationships between people that are already recorded in your business applications, such as:
    • Management hierarchies from your human resources system
    • Data on who worked on which deals, from your sales force automation system
    • Partner, customer, and partner supplier contacts along your supply chain system
    • People who work on similar transactions or projects within your operational systems

I could think of two benefits of having such a tool for an organization

1) I have experienced, being a PMO, sometimes it is very difficult to find out whether we have anyone with a particular skill in our organization, does anyone have prior experience on some problem, etc. Such information is very critical and can affect the way we deliver to our end clients. It is also frustrating that even if there are people in the organization who can help you out, you are simply not able to track them.

Having a Social Network Analyser or similar tool, can help you identify the right person and save a lot of time. Data is always reliable as it is fetched directly from the Business Applications.

2) Wouldn't it be of help if you know your team before you actually begin to work with them ? I think it is a great thing. More the team knows about itself, more productive it would be. It is fun for me to know hobbies, past work experiences, skills of my colleagues which i think improves the team dynamics :).

SAP has made available
demo version of the prototype with a preconfigured dataset. Check it out.

Screw dinner and a movie.

about 1 year ago | Megan Blocker: Queenie Takes Manhattan

Some people think dinner and a movie is a great date. I don't disagree, but I think dinner and a trip to the theatre is even better - especially when the play is actually cheaper than a ticket to a movie. Seriously.

Some of you have already heard me go on and on about Babel Theatre Project's latest production, Christmas is Miles Away, and some of you have (thus far) been spared. No longer.

Christmas is, in a word, awesome. It's funny, moving, gripping and entertaining. In short, you should go see it, as soon as humanly possible. If you need some convincing, maybe you should check out last Sunday's NY Times feature about the playwright, Chloe Moss, and her collaboration with Babel? That's right - NEW YORK TIMES, baby!

Or, you could have a look at the review on TheatreMania, which calls the performers "excellent" and praises Chloe's "keen ear for dialogue." And I agree, heartily.

If you can't make it to the play, or if you feel moved to further support such excellent theatre, please consider making a donation (large, small, in between) to Babel - Jeremy (my little bro) and Geordie (his partner in this most excellent venture) work their butts off to bring you great productions, and we want to make sure they're able to keep doing so. To donate, follow this link and click on "Support Babel." You can donate online or by sending a check. You choose!

Finally, the moment you've all been waiting for. If you go to see Christmas tonight or tomorrow, you can get in for just $9. NINE BUCKS for a night of theatre? Can't beat that, can ya? To get your $9 tickets, just enter the code "milesface" when making your purchase.

For all tickets - regular or discounted - follow this link to the TheaterMania box office, and go nuts.

Next, a list of potential pre- or post-theatre dining options, for your date-making convenience.

Perbacco (East 4th, between A & B)
A small, regional Italian joint with an excellent wine list. Stop in for pasta - or for the delicious apps, including a ridiculously good crostino misto plate. Just be sure to bring either cash or your AmEx - the only forms of payment accepted.

Kasadela
(East 11th, between B & C)
One of my favorite hidden gems, Kasadela is an Alphabet City izakaya. They serve small-to-medium size plates of traditional and modern Japanese food (but not sushi) meant to be enjoyed with a bottle of sake. Cheap, delicious, and you can pretty much always get in.

Death & Company
(East 6th, between 1st & A)
One of the best places for a cocktail in the whole of New York - and possibly, the world. Hyperbole? Go see for yourself before you judge.

Last but not least, full details for Christmas. Don't forget to come back and leave a comment telling me how much you loved the show...

CHRISTMAS IS MILES AWAY by Chloe Moss

May 6th - May 23rd, 2009
Wednesday - Saturday at 8 PM
The Connelly Theater
220 East 4th Street
Between Avenues A & B

Can you grow up together or do you have to do it alone? Time just won't stand still for Christie, Luke and Julie. As the eighties turn into the nineties, foreign wars loom and the Smiths continue to dominate their tape collection, but maturity and wisdom seem to be forever out of reach. In her critically acclaimed new play, set against the backdrop of working-class, music-rich Manchester, Chloe Moss takes on the inevitable and involuntary process of growing up.

Data Archiving Strategy

about 1 year ago | Nikhil Rao: Nix Talk

Last week I was conducting a Brainstorming session with my team to identify continuous improvement opportunities.
In this meeting it was surprising to get to know that some of the Key Transactional Databases has never had a data archiving policy defined.

In my opinion data archiving strategy should be a part of preventive maintenance activity for any firm. Database archiving solves a number of seemingly unrelated issues like improving performance and availability of resources, managing data retention policies and preserving database as long as required.

some of the benefits I can quickly list down are

Technical Benefits

  • Improvement in database performance post-archiving
  • Reduction of database size
  • Reduction in time taken for backups and refreshes (and thus quick resolution of some tickets too...)
  • Cost reduction for storage

Benefits for the Business
  • Performance improvement of all applications
  • Fewer occurrences of issues related to data corruption
  • Single source of data and no data reconciliation errors
  • Lower maintenance cost for the applications

Database archiving is an ongoing, continuous process not the one that is done periodically as in DB clean up.
Archiving strategies require one to work in planning such as classifying data. The sooner an organisation gets started with such a process the better is the preventive maintenance.

Consistently exceed sponsor expectations

about 1 year ago | Biju Bhaskar: Thoughts on enterprise application development...

This is the second of my series on the values we believe as an Application Development organization...

Let me start by defining what sponsors mean for us. As an AppDev organization, sponsors come to us with Application Development projects and we execute those projects so that we add value to the business. In our case most of them are internal clients. To take us to excellence in software development, we need to consistently exceed those sponsor expectation, so that they come back to us all the time happily, and never think of developing an application without us. As my colleague Mark puts it “Do your sponsors ask you to run an airline?” (He was referring to the zappos.com video on Nightline). We need to get to a state where our sponsors love us that much so that they ask us to run an airline. I know its hard .. but possible.

In the past (from my PMP days) exceeding sponsor expectation was all about delivering on time and on budget. Those days have gone for us. With the help of Scrum and timeboxed releases most of our projects are expected to be on time on budget. But then what is that matters? Is that scope? Not exactly… (1) setting the right scope, (2) sticking to commitments and (3) proper communication are the three things that are going to matter the most.

(1) Since scope is the only variable in the iron triangle how do we deal with it so that we exceed sponsor expectations? Its simple! Start with having a short vision for the time-boxed release by defining what business value are we going to deliver in the three months. If the project takes more than three months, break into smaller three month chunks. Make sure the stories (requirements) are prioritized to delight our users and aligned to the vision. Do release planning and tell sponsors what is possible and what is not possible in that release upfront based on the teams velocity. Understand what success criteria looks like for them. If it is not achievable, set the expectations upfront.

(2) Once you set the right expectation upfront, communicate... communicate... communicate! Scrum gives the framework for doing that. Doing Release planning, Sprint planning, daily stand-ups and sprint retrospectives the right way are key to this. Try to get time commitment from business so that they are available for the team when questions arise. I would recommend having them as part of the Product Owner team wherever possible. Similarly understanding and communicating risks are key as well.

Remember we are a service organization. We can never say “No, we can’t do it!”, or we can always say "Yes we can do it!". Instead, understand what they want and offer options so that it’s a win-win situation for everyone. Agile development gives a lot of flexibility to do this. Another important factor for success is to educate them when required. For example, if they are not aware of the benefits of automated testing, explain to them that... if they have an urgent change that needs to be done in a day, these automated tests can help them do that the same day, whereas manual testing would take few days. They will be convinced if we show them the benefits other projects have got from these kind of practices that is required for delivering quality applications.

(3) Once the team commits, it is important that we deliver most of the time. If we commit and don’t deliver, they will slowly lose trust in us. If its hard to commit due to lot of unknowns, we have to let them know that we need some more time to get more information before committing the deliverables.

Above all, what matters the most is how the team interacts with sponsors when things don’t go so well. We have to remember that every interaction is an opportunity. We can never keep them on the dark. Letting them know the bad news early and having different options or workarounds upfront would make a big difference in such situations.

These are simple things most of us know. We need to do this in every project so that we consistently exceed sponsor expectations. What are your thoughts on this?

Consistently exceed sponsor expectations

about 1 year ago | Biju Bhaskar: Thoughts on enterprise application development...

This is the second of my series on the values we believe as an Application Development organization...

Let me start by defining what sponsors mean for us. As an AppDev organization, sponsors come to us with Application Development projects and we execute those projects so that we add value to the business. In our case most of them are internal clients. To take us to excellence in software development, we need to consistently exceed those sponsor expectation, so that they come back to us all the time happily, and never think of developing an application without us. As my colleague Mark puts it “Do your sponsors ask you to run an airline?” (He was referring to the zappos.com video on Nightline). We need to get to a state where our sponsors love us that much so that they ask us to run an airline. I know its hard .. but possible.

In the past (from my PMP days) exceeding sponsor expectation was all about delivering on time and on budget. Those days have gone for us. With the help of Scrum and timeboxed releases most of our projects are expected to be on time on budget. But then what is that matters? Is that scope? Not exactly… (1) setting the right scope, (2) sticking to commitments and (3) proper communication are the three things that are going to matter the most.

(1) Since scope is the only variable in the iron triangle how do we deal with it so that we exceed sponsor expectations? Its simple! Start with having a short vision for the time-boxed release by defining what business value are we going to deliver in the three months. If the project takes more than three months, break into smaller three month chunks. Make sure the stories (requirements) are prioritized to delight our users and aligned to the vision. Do release planning and tell sponsors what is possible and what is not possible in that release upfront based on the teams velocity. Understand what success criteria looks like for them. If it is not achievable, set the expectations upfront.

(2) Once you set the right expectation upfront, communicate... communicate... communicate! Scrum gives the framework for doing that. Doing Release planning, Sprint planning, daily stand-ups and sprint retrospectives the right way are key to this. Try to get time commitment from business so that they are available for the team when questions arise. I would recommend having them as part of the Product Owner team wherever possible. Similarly understanding and communicating risks are key as well.

Remember we are a service organization. We can never say “No, we can’t do it!”, or we can always say "Yes we can do it!". Instead, understand what they want and offer options so that it’s a win-win situation for everyone. Agile development gives a lot of flexibility to do this. Another important factor for success is to educate them when required. For example, if they are not aware of the benefits of automated testing, explain to them that... if they have an urgent change that needs to be done in a day, these automated tests can help them do that the same day, whereas manual testing would take few days. They will be convinced if we show them the benefits other projects have got from these kind of practices that is required for delivering quality applications.

(3) Once the team commits, it is important that we deliver most of the time. If we commit and don’t deliver, they will slowly lose trust in us. If its hard to commit due to lot of unknowns, we have to let them know that we need some more time to get more information before committing the deliverables.

Above all, what matters the most is how the team interacts with sponsors when things don’t go so well. We have to remember that every interaction is an opportunity. We can never keep them on the dark. Letting them know the bad news early and having different options or workarounds upfront would make a big difference in such situations.

These are simple things most of us know. We need to do this in every project so that we consistently exceed sponsor expectations. What are your thoughts on this?

Bob Martin on Software Craftsmanship

about 1 year ago | Rajesh Rathod: Uncommon "Common Sense"!

Communicating risks

about 1 year ago | Prasoon Sharma: Enterprise Software Does not Have to Suck

How do you communicate project risks to your stakeholders? Is it effective? Does it help stakeholders -
- focus on the right risks?
- understand what you need from them or how can they help?

I've mostly used and seen a high/medium/low categorization and recently saw a simple and effective model (yes, I'm a sucker for models) that helped me zoom into the important issues right away (Thanks Erika and Daniel!)


How do you communicate risks? Does this model help? Can you improve it?

Bill Gates on the roll of technology in philanthropy

about 1 year ago | Amy Grandov: Technology for Social Innovation

This article, adapted from a speech by Bill Gates, is more than a year old, but the insights remain relevant today. Technology has an important role in philanthropy, but it's important to stay humble and realistic. Underserved people and communities often face significant challenges in using technology - illiteracy, lack of electricity, inability to maintain or upgrade equipment - that may undermine the best of intentions. Its best to take the time to understand local needs, culture, and resources/limitations before providing technology solutions.

Interestingly, technology may be most important in how it impacts potential donors. By communicating the extent of the need out there and connecting people in new ways, technology can help marshall the collective action necessary to make a real dent in major social challenges.

As Gates explains:"the Gates Foundation accounts for 1 percent of the giving in America. If we spent all of our endowment on education, it would amount to just half of what the state of California spends on education each year. If we used it to fill the gap between the amount of money that's available for health in developing countries and the amount that's needed, it would barely last one year."

Link:
http://money.cnn.com/2007/01/09/magazines/fortune/Gates_philanthropy.fortune/index.htm