This is part of the Chores series of posts
Last time we found the warm fuzzy feeling of green tests and a completed feature. Unfortunately, while that is a great feeling, our website is far from complete. We can however begin to leverage what we have learned so far to get this project moving. I write up my next feature for cucumber and save it in the features directory as define_children.feature.
Story: Define child As a parent I want to define my child(ren) So that I can assign them chores Scenario: Defining a child Given I am on the homepage When I follow "Add Child" And I fill in "child[nickname]" with "Bobby" And I fill in "child[open_identifier]" with "bobby.example.com" And I press "Add" Then I should see "Child added." And I should see "Bobby" Scenario: Defining a second child Given I am on the homepage When I follow "Add Child" And I fill in "child[nickname]" with "Bobby" And I fill in "child[open_identifier]" with "bobby.example.com" And I press "Add" And I follow "Add another Child" And I fill in "child[nickname]" with "Suzy" And I fill in "child[open_identifier]" with "suzy.example.com" And I press "Add" Then I should see "Child added." And I should see "Bobby" And I should see "Suzy"
Here are a few things that you can pick out of this feature.
- It infers that there is some sort of identity, probably with some sort of authentication at a future point.
- Identities will likely have roles of parent and child.
- The fact that the child is associated with an openID confirms that there will be authentication at some point.
- Identites have either a one-to-many or a many-to-many relationship.
I think (at this point) that I’m going to leave the actual authentication out of the scope of the feature. However it looks like there will be an Identity and some sort of relationship model in our near future. Notice also that I took advantage of some of webrat’s built in step defintions. I considered making a custom step to combine the entering of nickname, openId and pressing add, but I left it with the defaults for now.
Before we go ahead and create the models, let’s follow our feature and see where it leads us. Cucumber’s output looks like:
$ cucumber features Story: Define child # features/define_children.feature As a parent I want to define my child(ren) So that I can assign them chores Scenario: Defining a child # features/define_children.feature:6 Given I am on the homepage # features/step_definitions/chores_steps.rb:1 When I follow "Add Child" # features/step_definitions/webrat_steps.rb:8 Could not find link with text "Add Child" (RuntimeError) c:/Ruby/lib/ruby/gems/1.8/gems/webrat-0.3.4/lib/webrat/core/flunk.rb:4:in 'flunk'
So we will need to modify the homepage to have a link to add child and to do that we will need to have a url to go to. That means we need a controller. Since the link we are making is to add a child let’s call it the Children Controller.
$ ruby script/generate controller Children index new create exists app/controllers/ exists app/helpers/ create app/views/children exists test/functional/ create app/controllers/children_controller.rb create test/functional/children_controller_test.rb create app/helpers/children_helper.rb create app/views/children/index.html.erb create app/views/children/new.html.erb create app/views/children/create.html.erb
and update ./config/routes.rb to read
1 2 3 4 5 | ActionController::Routing::Routes.draw do |map| map.resources :chores map.resources :children map.root :controller => 'home' end |
and finally update our homepage view (./app/views/home/index.html.erb) to read
views
1 2 | <%= link_to "Add Chore", new_chore_path %> <%= link_to "Add Child", new_child_path %> |
Let’s check back with Cucumber and see how we did.
$ cucumber features Story: Define child # features/define_children.feature As a parent I want to define my child(ren) So that I can assign them chores Scenario: Defining a child # features/define_children.feature:6 Given I am on the homepage # features/step_definitions/chores_steps.rb:1 When I follow "Add Child" # features/step_definitions/webrat_steps.rb:8 And I fill in "child[nickname]" with "Bobby" # features/step_definitions/webrat_steps.rb:12 Could not find field labeled "child[nickname]" (RuntimeError) c:/Ruby/lib/ruby/gems/1.8/gems/webrat-0.3.4/lib/webrat/core/flunk.rb:4:in 'flunk'
Not bad at all the step passed and it is now looking for the form on the new view. Let’s make it by editing /app/views/children/new.html.erb to read:
1 2 3 4 5 6 7 8 9 10 11 12 13 | <% form_for(@child) do |f| %> <%= f.error_messages %> <p> <%= f.label :nickname %><br /> <%= f.text_field :nickname %> </p> <p> <%= f.label :open_identifier %><br /> <%= f.text_field :open_identifier %> </p> <%= f.submit "Add" %> <% end %> |
Let’s also remove ./app/views/children/create.html.erb file while we are at it, since we won’t need a view for this method.
Hmmm. hold on for a second. We are referencing an instance of @child that doesn’t exist. That’s definately going to fail. We need to add a model to define relationships between identities not to mention the identities themselves.
$ ruby script/generate model Identity identifier:string exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/identity.rb create test/unit/identity_test.rb create test/fixtures/identities.yml exists db/migrate create db/migrate/20090124055031_create_identities.rb
and
$ ruby script/generate model Child parent_id:integer child_id:integer exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/child.rb create test/unit/child_test.rb create test/fixtures/children.yml exists db/migrate create db/migrate/20090124055548_create_children.rb
When we return it will be time to edit the migrations and run them and then dive back into Test::Unit.
Jamal,
Sorry to keep bugging you, but what should the new child view be named?
It should be app/views/children/new.html.erb
Yep, rails handles pluralization / singularization by itself.
I am having some trouble with seeing your blog layout in the most recent release of Opera. Looks fine in IE and Firefox however.Have a great day.
Thanks for letting me know, I’ll have to check it out.