Category Archives: Development

Development with MongoMapper

A question popped up:

Mongo is schema-less, that means we can create new fields when needed, I read the mongo mapper document, it still needs to write model code like below, so we have to change the code below when we need new field, is this kind of limitation to use the schema-less database mongodb?

class User
  include MongoMapper::Document

  key :first_name, String
  key :last_name, String
  key :age, Integer

Strict answer: NO, you do not have to change the model code to add a new “column” to your “table.”

I like to think of MongoMapper as making my domain classes behave more like an object-oriented database than a data management layer.

During rapid development, having a database that just follows along with your model makes for speedy feature creation and prototyping. Though “migrations” being first-class citizens, of sort, in Rails is a great step forward for managing development changes with traditional schema databases, MongoDB doesn’t even require that level of concern.

That said, it also implies you, as the developer/designer/architect, are treated as an individual willing to take on the responsibility of wielding this amount of “power” (just like Ruby does).

Therefore, even though you do not technically have to add keys to your MongoMapper document class, if you are talking about core aspects of your domain, I would add the keys so as to make it clear what you are modeling.

Now, there may be certain cases where a class is just storing a bunch of random key-value pairs that are not key elements of your domain, with the sole purpose of merely showing them later. Maybe you are parsing data or taking a feed of lab results, for example, and just need to format the information without searching or sorting or much of anything. In this situation, you do not need to care about adding the (unknown) keys to the model class.

As the saying goes, “just because you *can* do something does not mean you *should* do something.”

You Can Start at Login!

On one of the lists I hang out at, Marton was wondering about how to start off a project that required authenticated users…

How would you decouple the sign-up feature from the login feature to keep the stories independent and testable from the UI only. The acceptance criteria should not fiddle with any implementation details such as concrete url-s or field types. I’d like to leave that entirely to the developers. Let’s say I have the following story coming to mind in a workshop:

As an Anonymous user I want to sign up to Example.com website to enjoy the benefits of a registered user.

Acceptance Criteria:
1. I navigate to the signup page
2. I enter my full name, desired username and my password
3. I have to verify my password to avoid any typos
4. I submit my information

And here comes the “tricky” bit:
5. I can log in with the credentials I provided.

Some folks suggested he start on real functionality first, others implied login was a lousy first story.

My take: It’s not a hard story to start at and have a meaningful test that can grow over time.

For example, to start, you can simply check that the response has “Login Succeeded” ( or “Login Failed” for testing that a bogus login attempt does indeed fail).

In Cucumber flavor:

Scenario: Registering as a new user
    Given I am a new user
    When I visit the site
    Then I can register

Scenario: Logging in as a registered user
    Given I am a registered user
    Then I can login
    And enjoy the beauty of the website

Or, even more simply:

Scenario: Successful Login
    When I login as admin
    Then I should be logged in

Scenario: Failed Login
    When I login as asdf56ghasdkfh
    Then I should be not logged in

And your steps would hide the logic for filling in the login form and checking for success:

Given /^I login as "([^"]*)"$/ do |login|
  @login_name = login
  visit login_path
  fill_in "login", :with => login
  fill_in "password", :with => "password"
  click_button "login_button"
end

Then /^I should be logged in$/ do
  response.should contain "Login Succeeded"
end

Then /^I should not be logged in$/ do
  response.should contain "Login Failed. Please try again."
end

Your login details can change over time, adding the password confirmation box, handle validation errors, etc.

Your next step might be to show Admin-user-only functionality as I have here (snagged from a current app):

Feature: Quickly exercise the primary UIs just to make sure nothing blows up

  Background: We need to pre-populate the database with the simulator results, and be logged in as admin
    Given I login as "admin"

  Scenario: Brief tour around the Admin UI
    Then I should be able to click on "Dashboard" and see "Admin Management"
    And I should be able to click on "Accounts" and see "Search"
    And I should be able to click on "Sign out" and see "Login to Your Account"

And so it goes, step-by-step.

Hope that helps!

As an update… one of the list contributors went so far as to indicate “Login has Zero business value, always.” No wiggle room there!

well, okay, if you are parsing the act of logging in to achieve a status of an authenticated user to provide a means of secure access as separate from the need to have secure access, well, ok.

yes, i didn’t separate the two. The point was merely to show the OP how you could easily write his desired login and registration story, and it is not that hard.

As an aside, another project I did with two friends required a “marketing” site where you could sign up and see info about the core application. The project also required the site where registered users would do the real work of the application.

Since I knew login would be easy to add, I suggested to my one friend how to do it, and proceeded ahead with the other functionality. This was based on knowing full well that I would be able to feather in the user authentication and access rights into the core app once they were completed in the marketing app.

So, I am not hard over one way or the other on this issue, and in the past 12 months have done it both ways on different projects. Hence my surprise at folks’ having such stark “black and white” edicts banning ever starting at Login as a story.

Now, were I on a project where there was some very risky bit that, should we not solve that problem adequately, nothing else matters, guess where we start? Not login. 🙂

Geesh.

Oh, George posted a reply of sorts here.

Pair Programming Comments

Yves Hanoulle had some questions from class participants on his post about Pair Programming. I am not a very experienced pair programmer, but that didn’t stop me from providing some answers 🙂

* Can you PP over skype?

Yes — or other similar screensharing technologies (iChat) that allow you to switch control. @jbrains and I did pairing for a code retreat a couple of months ago. You can see the code and a video link here on github.

* Do we need somebody to ‘supervise’ the way you do PP ? (Esp in the beginning?)

Might not be a bad way to more quickly learn from someone else’s tips and techniques. But even better, just switch up the pairing so that you gain insights/ideas from other people with more experience.

* What if there’s no option possibility to use some OS/Computer

With no computer to program on, you would have to stretch the limits of the definition of pair programming I suppose. Pair Yapping About Programming — P-YAP?

* What to do if there is a conflict between the two, a discussion??

Try and sketch out the competing ideas in code. Unless the argument is about which beer is best… then you need to take it to the bar and do a double-blind taste test.

* It can’t work with any type of character, how do you manage?

Pairing should be optional.

* What if one uses AZERTY and another one QWERTY keyboard?

You could solve that with technology.

* Doesn’t it make it harder to plan a project or resources people (Yves re-framed resources to people)

I would suspect the team that pairs is not that much different than a team that doesn’t pair. Both teams are probably lousy at estimating <g>. Instead of stressing at how PP affects your team, just make an initial guess at your estimates and alter the guess after each iteration.

* Can someone do PP with 1 person and PP for something else with another person?

I don’t understand the question. If you mean simultaneously, no. If you mean one time someone does Pair Programming with person X, and later does Pair Painting with Person Y — sure, this is possible. But what does it have to do with anything?

* Can you get into “the zone” when you’re PP-ing?

Probably. You’ll just have to try it and see.

* Does Promiscuous Pairing kill the flow? (30′ interrupts)

Never tried it. Let the team try it and see what happens.

* Why not use PP all of the time?

Let the team try it and see what happens.

* PP = More talking = more annoying for other nearby teams?

It is more annoying for people that are bothered by such environments. I suppose some people prefer quiet.

* Do you plan who is going to do what or how do you choose whose turn it is?

Let the team decide.

* Can you do PP with > 2 people?

You can do whatever you like. Just observe if it is effective or not. I suspect you might find diminishing returns.

* How do you handle the “Don’t care”?

What does this have to do with PP? If you have done everything humanly possible to help someone become a productive member of the team and they are intent on being a-holes; and you have warned them of the consequences of being an a-hole to the team; then fire them so that the team morale is not broken by “one bad apple.”

Cucumber Parser Smarter Than Me

So that I don’t lose another 15 minutes… I had a step like this:

Given a valid outpatient A01 Admit message (without extra ZP1 segment) with Patient Num "12345678"

And in the steps.rb file:

Given /^a valid outpatient A01 Admit message (without extra ZP1 segment) with Patient Num "([^"]*)"$/ do |pn|

Which happily kept not working:

You can implement step definitions for undefined steps with these snippets:
And /^a valid outpatient A(d+) Admit message (without extra ZP(d+) segment) with Patient Num "([^"]*)"$/ do |arg1, arg2, arg3|
  pending # express the regexp above with the code you wish you had
end

UGH!

After getting rid of A01 and ZP1, I still had this “error,” but it led me to realize it was ALL in the parentheses in the steps.rb file! Why? Because parentheses are valid regex elements. Duh. Once I escaped those, all worked like a champ:

Given /^a valid outpatient A01 Admit message (without extra ZP1 segment) with Patient Num "([^"]*)"$/ do |pn|

Mystery solved.

MongoMapper Query Overview

There was a question on the MongoMapper Google Group from a Mongoid user about how MongoMapper handles associations. Brandon was surprised that this query returned an Array:

Product.first.releases.where(something)

Let’s break it down, one bit at a time and clear things up:

# This would be an instance of Product
Product.first # Class.

This simply gets the first element in the Array that is returned by the default “All” query on Product. Of course, without sorting, you probably would not want to do this.

# This would be a return value of an array, assuming Product <>----> * Release
Product.first.releases # Array.

In Brandon’s example, I assume “releases” is a many association. That means, an Array. Unless the association has been tweaked to have default sorting via an Association Extension, getting the “first” one might be adventurous.

# This doesn't change the above... merely adds a restrictive query clause
Product.first.releases.where(something) # Array.

Here we simply get the first element of the releases array, narrowed down by the “something” query.

Capisce?

I am not sure why, but for me it seems more logical to start my clauses with the where, and narrow them down further, or modify them… In MongoMapper, I find querying rigor is much more “loose” than say a SQL SELECT query that requires things in proper order… I would tend to write my queries in more or less this fashion:

ModelClass.where(some criteria).[sort | order | another where clause | fields | limit].[all | first | paginate]

In addition, it is important to note that MongoMapper returns a query and does not actually perform the query until you add something that needs the results. For example: all, first, paginate, sort, etc.

I can picture one of those “man page” or SQL style of fancy ways to show you how you can construct a mongomapper query given all the combinations of options for each “position” in the query…

My (unsolicited) advice is to make the query look as “natural” as possible in terms of how you might read it aloud.

Product.releases.where(:major.gt => 1).sort(:minor.desc).first # Get the latest 1.x release

(And, if the releases where clause query is common, you can create an Association Extension)

Use the Console

You can always just output the queries to the console:

>> Patient.where(:last_name=>/john/i).class
=> Plucky::Query
>> Patient.where(:last_name=>/john/i).all.class
=> Array
>> Patient.where(:last_name=>/john/i).all.count
=> 1
>> Patient.where(:last_name=>/john/i).first.class
=> Patient
>> Patient.sort(:created_at.desc).first.class
=> Patient

Association Extension

And to show an example of an extension (when you use it frequently, for example):

class Encounter
  include MongoMapper::Document
  ...
  # Associations :::::::::::::::::::::::::::::::::::::::::::::::::::::
  many :events, :limit => 30, :order => 'msg_timestamp desc' do
    ...
    def images
      where(:type => [EventConstants::EventType.to_text(EventConstants::EventType::IMAGE)]).order(:created_at.desc).all
    end

    def charts
      where(:type => [EventConstants::EventType.to_text(EventConstants::EventType::ED_SUMMARY)],
            :file_version.in => ["P", "F"]).order(:created_at.desc).all
    end

    def admits
      all(:type => [EventConstants::EventType.to_text(EventConstants::EventType::ADMIT)])
    end
  end
  ...
end

# For a given encounter
enc=Encounter.find('4dadad188951a20727000160')
>> enc.events.images.count
=> 7
>> enc.events.images.class
=> Array
>> enc.events.images.first
=> #

Named Scope

If you will need dynamic querying, you could use a Named Scope as follows:

scope :by_days_old,  lambda { |age| where(:msg_timestamp.gt => age.days.ago) }

This can be used as follows:

Encounter.by_days_old(10)
=> #Fri Apr 15 03:35:53 UTC 2011}>

Looking at Gem Code is Easy with GemEdit

Ever want to pop into the source code of some gem that you are using?

Gem Edit is a nice and easy way to do this (if you aren’t using RubyMine, for example):

[sudo] gem install gemedit

In the terminal, simply type:

[develop*]$  jonsmac2-2:source jon$  gem edit -e mate mongo_mapper

And you will see:

Found gem for 'mongo_mapper' with version >= 0
Opening the following gems with mate:
  mongo_mapper-0.8.6 /Library/Ruby/Gems/1.8/gems/mongo_mapper-0.8.6
Running `mate "/Library/Ruby/Gems/1.8/gems/mongo_mapper-0.8.6"`

and Voila, Mongo Mapper appears in TextMate:

Mongo Mapper

Mongo Mapper Source Code

In an IDE, you can often get to the source code for a single method, but not as “completely” as with gemedit and TextMate, IMHO.

 

Mongo Mapper from IDE

Mongo Mapper from IDE

 

@martinstreicher gave me a good tip when using bundler (which I use on my Rails 3 apps):

export EDITOR=mate;bundle open <gem>

Factory Girl and MongoMapper

You were probably hoping for some Rosey the Riveter poster…

Factory Folder

Factory Folder

Instead, I am going to extend my small MongoMapper example to include Factory Girl. The steps are pretty simple:

  1. Go here to install…
  2. Create your factories
  3. Use the factories in Cucumber/RSpec

Factory Construction

I created a new “factories” folder under the spec folder:

The factories for User and Event are quite simple:

Factory.define :user do |u|
  u.name ('a'..'z').to_a.shuffle[0..7].join.capitalize
end

and

require 'factory_girl'
def dummy_word(len=6)
  ('a'..'z').to_a.shuffle[0..len].join.capitalize
end

def dummy_date
  secs_in_day = 24*60*60
  Time.now + (rand(60)*secs_in_day - 30)
end

Factory.define :event do |e|
  e.title "#{dummy_word} #{dummy_word 3} #{dummy_word 10}"
  e.date  dummy_date
end

Refactor Original Setup

Instead of using this style of test data creation:

@event = Event.create(:title => "Code Retreat Timbuktoo", :user => @fred)

We will use the new factory as follows:

@event = Factory(:event, :title => "Code Retreat Timbuktoo", :user => @fred)

Refactor Cucumber

The given went from this:

Given /^A set of events$/ do
  fred = User.find_or_create_by_name("fred")
  (1..10).each do
    Event.create(:title=>"#{dummy_word} #{dummy_word 3} #{dummy_word 10}",
                 :date => dummy_date,
                 :user => fred)
  end
  harry = User.find_or_create_by_name("harry")
  (1..10).each do
    Event.create(:title=>"#{dummy_word} #{dummy_word 3} #{dummy_word 10}",
                 :date => dummy_date,
                 :user => harry)
  end
  Event.count.should == 20
end

to this – including refactoring out dummy_title, and reducing it to one loop:

Given /^A set of events$/ do
  fred = User.find_or_create_by_name("fred")
  harry = User.find_or_create_by_name("harry")
  (1..10).each do
    evt = Factory(:event, :title => dummy_title,
                          :date  => dummy_date,
                          :user  => fred)
    evt = Factory(:event, :title => dummy_title,
                          :date  => dummy_date,
                          :user  => harry)
  end
  Event.count.should == 20
end

Subtle Details

The beauty of having tests is that I could easily mess around with getting some of the Factory Girl configuration stuff in the right place. Try something, run the test, adjust as needed until all are back to green.

The file features/support/env.rb got some additions so that Cucumber could find the factories:

$LOAD_PATH << File.expand_path('../../../app/model' , __FILE__)
require 'user'
require 'event'
require 'spec/factories/events.rb'
require 'spec/factories/users.rb'
load 'config/mongo_db.rb'

All the tests still pass!

More Complicated Example

For a project I work on, my factories look like this, with auto-creation of random IDs:

def random_months(months)
  day_in_secs = (24*60*60)
  (1+rand(months))*30*day_in_secs
end

# ----------- GROUP -----------
Factory.sequence :group_num do |n|
  "99#{n}#{rand(n)}"
end

Factory.define :group do |g|
    g.group_num {Factory.next(:group_num)}
    g.name "Greatest Group"
end
# ----------- ACCOUNT -----------
Factory.sequence :doctor_num do |n|
  "999992#{n}#{rand(200+n)}"
end

Factory.sequence :login do |n|
  "AB#{rand(n*68)}bx#{rand(200+n)}"
end

Factory.sequence :msid do |n|
  "CQ987Z12#{n}#{rand(n)}"
end

Factory.define :account do |a|
  pw = 'password'
  a.msid { Factory.next(:msid) }
  a.doctor_num { Factory.next(:doctor_num) }
  a.first_name "James"
  a.last_name "Jones"
  a.role 'user'
  a.password pw
  a.password_confirmation pw
  a.email Setting.get("AutoEmail")
  a.login { Factory.next(:login) }
end

# ----------- PATIENT -----------
Factory.sequence :patient_num do |n|
  "#{n}#{rand(300+n)}"
end

Factory.define :patient do |pt|
#  pt.patient_num "10000009"
  pt.patient_num {Factory.next(:patient_num)}
  pt.emr_num "1853286"
  pt.first_name "John"
  pt.last_name "Johnson"
  pt.dob {(Time.now - random_months(36))}
  pt.count_public_encounters 1
  pt.count_public_events 2
end

 

Cucumber, RSpec, MongoMapper, Git, Oh My!

Nick left a question on my many-to-many associations post. He wanted to know more about sorting by date and querying…

So I decided to (over achieve and) show how I would approach that as if I were adding a new feature:

  • Adding a “date” key field and an index
  • Using Cucumber to drive the new feature from the desired behavior à la BDD.
  • Querying with a date sort tacked on…

You can follow my progress from the earlier version to this one by examining the commit history:

Commit History

Commit History for Adding Dates to the Event Class

Looking at the “added initial event date functionality” commit, you can see how I added some new files to allow for Cucumber and MongoMapper:

Commits for Event Dates

Commits for Event Dates

For Cucumber, I added the “/features” stuff.

And since I wanted to start testing the code, I had to make the database functional, so I added “mongo_db.rb” – and I assume you have MongoDB installed and running locally.

##### MONGODB SETTINGS #####
MongoMapper.connection = Mongo::Connection.new('localhost', 27017, :pool_size => 5)
MongoMapper.database = "event-development"

I am never quite sure if there is a “perfect” way to wire up small, non-Rails apps like this one to use MongoDB. But what I have done works good enough to allow for a simple example to run.

BDD Cycle

So I began the BDD cycle by creating a “feature branch” and switching to a new branch from the current master branch:

git checkout -b event_dates master

Next I wrote the feature for the new behavior:

Scenario: Sort Events by Date
  Given A set of events
  When I display the events
  Then I should see them sorted by latest date first

When you run Cucumber, you will get the default code for steps – all pending of course.  Naturally, I did one step at a time, to take each one from “pending” to green. Working on the Given, then the When, and finally the Then, I came up with these steps:

Given

Here I wanted to generate a set of data so that we could see if the list was sorted properly. You can check out the code on github for the randomness baked into the “dummy_*” helper methods. And I wanted to create the events for two users.

Given /^A set of events$/ do
  fred = User.find_or_create_by_name("fred")
  (1..10).each do
    Event.create(:title=>"#{dummy_word} #{dummy_word 3} #{dummy_word 10}",
                 :date => dummy_date,
                 :user => fred)
  end
  harry = User.find_or_create_by_name("harry")
  (1..10).each do
    Event.create(:title=>"#{dummy_word} #{dummy_word 3} #{dummy_word 10}",
                 :date => dummy_date,
                 :user => harry)
  end
  Event.count.should == 20
end

When

Sort of playing along as if this is a web request, I coded this step to return a “response” that is generated by the “list all events” class method. In true BDD fashion, this is the code I wish I had 🙂

When /^I display the events$/ do
  @response = Event.list_all
end

Then

The proof is in scanning the resultant “response” object to ensure date order is correct:

Then /^I should see them sorted by latest date first$/ do
  first = Date.parse(@response.third[0..10])
  last = Date.parse(@response.last[0..10])
  first.should > last
end

Outside – In

As soon as I ran the “When” I got a failure due to Event.list_all not existing. So off to the RSpec-land we go, to write the expectations for list_all. This is known as the “Outside-In” approach. (I learned this term from the excellent RSpec book, and it looks like you can watch a video about it here.)

The behavior expressed above (in Cucumber) can be thought of as more of an “outer,” acceptance/integration style of test. Typically it would be the User Interface (UI) – but I have been known to blur that line, since not all code is about UI and since Cucumber is so darn fun to use. Working at this outer level often leads to expressing what is expected of our actual code; in this case, that Event have a class-level method that returns a list of it’s instances (a.k.a., documents). Since we are talking about the behavior of a class, that is more of the “inside” of the application. Not something that an external user might care so much about directly, but rather something that supports the end behavior in an indirect fashion. For the “inside” we turn to RSpec (basically a better-than-unit-test, unit test tool).

  • Outside ≈ Feature ≈ Cucumber
  • Inside ≈ unit test ≈ RSpec
  describe "#list_all" do
    it "should show each event, ordered by date" do
      response = Event.list_all
      response.should_not be_empty
      response.class.should == Array
      response.size.should == Event.count + 2 #for title and column header
      # Yes, you should not output stuff as part of your tests, but this *is* our UI 🙂
      puts response
    end
  end

Many times, my initial pass at a new method is to simply return what is expected. Then write another test to make that fail. Sort of “sneak up on the answer.” But here it was easy enough to simply output some real text from the get-go:

  def self.list_all
    response = []
    response << "%s %s %s" % ["*"*10, "LIST OF EVENTS", "*"*10]
    response << "%6s %15s               %s" % ["Date", "TITLE", "Attendees/Interested/Likes"]
    events = Event.all(:order => 'date desc')
    events.each {|e| response << e.to_summary}
    response
  end

Oops. LOL (:-D) While writing this post, I found a mistake when testing my code a bit further than my initial commit.

I decided to remove the order part of the query, which revealed that the Cucumber feature still passed. Crap! So, it wasn’t so easy after all! Dope.

    events = Event.all

Second Attempt

My initial way of generating records resulted in the documents magically being in the right date order by default. Tests passed, but the test was wrong – not vigorous enough testing!

Note to self:
no matter how trivial things seem, write failing tests
that contradict each other – so to speak.

So, I tweaked the document generator to better randomize the list of events such that we won’t accidentally have them all in proper order by default:

  ...
  fred = User.find_or_create_by_name("fred")
  (1..10).each do
    Event.create(:title=>"#{dummy_word} #{dummy_word 3} #{dummy_word 10}",
                 :date => Time.now + (rand(60)*secs_in_day - 30),
                 :user => fred)
  end
  ...

And, instead of just spot-checking the order, here is a new RSpec test to ensure each event is in proper order, date-wise:

    it "should show each event, ordered by date" do
      response = Event.list_all
      response.should_not be_empty
      response.class.should == Array
      response.size.should == Event.count + 2 #for title and column header
      r_prior_date = Date.parse(response[2][0..10])
      response[3..response.size].each do |r|
        date = Date.parse(r[0..10])
        date.should < r_prior_date
        r_prior_date = date
      end
      # Yes, you should not output stuff as part of your tests, but this *is* our UI 🙂
      puts response
    end

Now we’re talking! A failed test:

'Event#list_all should show each event, ordered by date' FAILED
expected: < Wed, 20 Apr 2011,
     got:   Wed, 20 Apr 2011

And similarly, I re-wrote the Cucumber test. Funny thing, further testing revealed that the error above was not actually a legitimate fail as it turns out! I discovered I needed “<=” instead of just “<“– sometimes the simplest things aren’t so simple after all. Especially when it comes to setting up sample data.

Then /^I should see them sorted by latest date first$/ do
  last_date = Date.parse(@response.third[0..10])
  @response[3..@response.size].each do |r|
    date = Date.parse(r[0..10])
    date.should <= last_date
    last_date = date
  end
end

And I got the above test to fail by “stepping back” and removing the “order by” clause to get me back to an original, non-sorted listing. Good! Now we can step forward again and try to get the functionality that we are looking for to work.

Cucumber Failing Tests

Cucumber Failing Tests

I re-enabled the order clause to see if the tests would now pass:

events = Event.all(:order => 'date desc')

And, fortunately, the tests are indeed passing:

Cucumber Passing Tests

Cucumber Passing Tests

Commit on Green

Once you get the bits of functionality working, commit (even if you still have pendings). Committing locally has no downside 🙂 Here I will commit and push to the repo (the “$” is my prompt (well, not really), and the #comments are not part of the command line!):

$git status #You can see your changes
$git commit -a -m "added initial event date functionality"  #commit your changes
$git checkout master #switch to the master branch
$git merge --no-ff event_dates #merge all of your local feature branch commits, preserving each
$git push origin master #Pump it up to the repo
$git branch -d event_dates #Get rid of the feature branch

This rhythm gets to be very familiar.

More on Querying

You may have noticed some of the queries above, and this was one of Nick’s questions…

With MongoMapper, you can chain Plucky queries as follows:

  def self.list_all(a_user=nil)
    response = []
    response << "%s %s %s" % ["*"*10, "LIST OF EVENTS", "*"*10]
    response << "%6s %15s               %s" % ["Date", "TITLE", "Attendees/Interested/Likes"]      events = nil     if a_user.nil?       events = Event.all(:order => 'date desc')
    else
      events = Event.where(:user => a_user).all.sort(:date.desc)
    end
    events.each {|e| response << e.to_summary}
    response
  end

I added a new feature that shows off the above query, quickly ran through the entire process again, from git checkout to git push, with Cucumber and RSpec and code in between. You can find it all in the source code.

Cucumber Show Events For User

Cucumber Show Events For User

Git is really an amazing revision control tool… I can’t imagine using anything else now. Here is an example of looking at the “Network Graph” of my little project:

github network graph

Github Network Graph

Pow — A Great Server for your Mac Bat Cave

Somehow I stumbled across this great little tool  — oh yeah, John Nunemaker mentioned “powder,” which was “Syntactic sugar for http://pow.cx/

Huh? Syntactic what? For “pow” what? John hasn’t steered me wrong yet, so I decided I needed to look at what Pow was. In 37Signals own words:

Pow: Zero-configuration Rack Server for Mac OS X

In other words:

You can run a bunch of your rails apps all at once, with ease.

This is worth the effort to try and get running to see if it will help ease how you work with multiple Rails apps.

Since my experience was a bit off from the awesome-looking Screencast teaser, I figured I would share it in case others might benefit from the troubleshooting.

Once I solved the Pow-not-working-like-magic-from-the-start problems, it worked right out of the box with a Rails3 App. Not so much with my Rails2 apps. So, you can either try to do it the Rails3 way from the start (see below for instructions), or barge ahead and see how far you get (knowing now what I do for Rails2, barging is probably a pretty safe bet).

Yes, I am repeating what is in the main website… but then aggregating common troubleshooting experiences ad fixes below, to save you (and my colleagues) time.

Install Pow:

$ curl get.pow.cx | sh

Be certain you see “*** Installed” or it is not! (See Troubleshooting section below if need be.)

jonsmac2-2:.pow jon$ curl get.pow.cx | sh
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
Dload  Upload   Total   Spent    Left  Speed
100  2722  100  2722    0     0  17322      0 --:--:-- --:--:-- --:--:-- 34455
*** Installing Pow 0.2.2...
*** Installing local configuration files...
*** Starting the Pow server...
*** Installed

If you get upset, just uninstall:

$ curl get.pow.cx/uninstall.sh | sh
Symbolic Link to Rails3 App

Symbolic Link to Rails3 App

Configure:

$ cd ~/.pow
$ ln -s /path/to/myapp

To the right is an example. Name the link if you do not want to use the default folder name. For example:

ln -s ~/railsprojects/first_app jkfirstapp

This allows you to then enter the following into the browser, using the symbolic link name (or the default folder name):

http://jkfirstapp.dev

If that didn’t work, continue onward, your journey will be short (I hope).

Troubleshooting

I was disappointed when the magic didn’t happen right away. Boy does the Ruby community spoil us! So a hunting I will go…

Create a Rails3 App

If you are only doing Rails2, see below for the config.ru fix. Otherwise, creating a vanilla Rails3 app is a good way to test that Pow is properly configured. Here is a simple Rails3 app (from Michael Hartl’s Ruby on Rails3 Tutorial):

mkdir ~/railsprojects
rails new first_app

edit the Gemfile:

gem 'rails', '3.0.1'
gem 'sqlite3-ruby', '1.2.5', :require => 'sqlite3'

Then execute:

bundle install
rails server

It should be running with the default server page.

I got Nothing!

If pow did not install, or you get seemingly NOTHING when going to the browser webpage, look no further than here. The following worked for me (and others). Seems that the permissions are not quite right sometimes:

before:

-rw-rw-r--   1 jon  staff   518B Apr 18 13:42 cx.pow.powd.plist

So I ran this:

jonsmac2-2:.pow jon$ launchctl load -Fw ~/Library/LaunchAgents/cx.pow.powd.plist
jonsmac2-2:.pow jon$ chmod 644 ~/Library/LaunchAgents/cx.pow.powd.plist
jonsmac2-2:.pow jon$ curl get.pow.cx | sh

And, after the re-install, the perms ended up as you might expect:

-rw-r--r--   1 jon  staff   518B Apr 18 13:42 cx.pow.powd.plist

Checking It’s Running

This is admittedly odd output for a “working” install, but it gives you at least one data point to compare what you get versus this. Do the following:

cd ~/Library/Application Support/Pow/Current/bin
jonsmac2-2:bin jon$ ./pow

On my Mac it results in:

node.js:134
    throw e; // process.nextTick error, or 'error' event on first tick
    ^
Error: EADDRINUSE, Address already in use
at HttpServer._doListen (net.js:1089:5)
at net.js:1060:14
at Object.lookup (dns.js:159:5)
at HttpServer.listen (net.js:1054:20)
at Array.<anonymous> (/Users/jon/Library/Application Support/Pow/Versions/0.2.2/lib/daemon.js:34:27)
at EventEmitter._tickCallback (node.js:126:26)

Domain Isn’t Setup

If you see this:

No such app

No such application can be found!

Then you know you have screwed up the symbolic link.

Try again, and be careful and exact.

Trouble Accessing Dev domains

Some folks needed this simple fix:

touch /etc/resolver/dev

Rails2: Cannot GET /? –> config.ru is Missing!

That’s right, you see: Cannot GET / in the browser. Bet you never saw that before!

This means that you are missing the Rackup config.ru file in your application’s root. Try adding this file (you can see it in the folder screenshot above):

# This file is used by Rack-based servers to start the application.
require "./config/environment"
use Rails::Rack::LogTailer
use Rails::Rack::Static
run ActionController::Dispatcher.new

Pow Can’t Start Your App

This is most likely, genuinely, truly your error… Sorry to say!

The error below is because the config.ru was completely wrong (I was trying the Rails3 project file (duh — it invokes a class in a module named after the app itself)):

Pow can’t start your application.

/Users/jon/railsprojects/track_my_league/tml raised an exception during boot.
NameError: uninitialized constant FirstApp
/Users/jon/.gem/ruby/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:443:in `load_missing_constant'
/Users/jon/.gem/ruby/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:80:in `const_missing'
/Users/jon/.gem/ruby/1.8/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:92:in `const_missing'
/Users/jon/railsprojects/track_my_league/tml/config.ru:4
/Users/jon/Library/Application Support/Pow/Versions/0.2.2/node_modules/nack/lib/nack/builder.rb:4:in `instance_eval'
/Users/jon/Library/Application Support/Pow/Versions/0.2.2/node_modules/nack/lib/nack/builder.rb:4:in `initialize'
/Users/jon/railsprojects/track_my_league/tml/config.ru:1:in `new'
/Users/jon/railsprojects/track_my_league/tml/config.ru:1

Here the error is that I do not have the gem environment set up properly with RVM (using .rvmrc). Easily diagnosed because I can’t even start the app manually!

SystemExit: exit
./config/boot.rb:66:in `exit'
./config/boot.rb:66:in `load_rails_gem'
./config/boot.rb:54:in `load_initializer'
./config/boot.rb:38:in `run'
./config/boot.rb:11:in `boot!'
./config/boot.rb:110
./config/environment.rb:7:in `require'
./config/environment.rb:7
/Users/jon/railsprojects/tml/TML/config.ru:3:in `require'
/Users/jon/railsprojects/tml/TML/config.ru:3
/Users/jon/Library/Application Support/Pow/Versions/0.2.2/node_modules/nack/lib/nack/builder.rb:4:in `instance_eval'
/Users/jon/Library/Application Support/Pow/Versions/0.2.2/node_modules/nack/lib/nack/builder.rb:4:in `initialize'
/Users/jon/railsprojects/tml/TML/config.ru:1:in `new'
/Users/jon/railsprojects/tml/TML/config.ru:1

Hope this helps!