Testimony Part III: Adding Users and tests


Applications are worthless without users. Really, what’s the point of writing a hot rails-based web app if no one uses it? So what kind of users does Testimony have? If you think about it, you’ll realize that we have two distinct types of users: the site owner (or administrator), and happy customers that leave testimonials. So in reality, we have a couple of different use cases to develop, one for the normal consumer, and one for the administrator.

Just so we have some useful language that we can use to talk about our users, let’s define some roles.

  • Julie - Julie is our customer. She is the site owner, and since it’s a small shop, she is also the administrator of the Testimony application
  • Rachel - is a normal user. A happy satisfied customer that wants to tell the world how great her portraits came out.
  • Jesse is another happy customer… we want to have many of them!

Use Case 1: Rachel

Rachel came in for a photo shoot. Her session went well, and she just got her prints today. Awww, so cute! Look at that smile! She’s just so happy, she has to tell someone. So she does. She opens up her browser, goes to the studio homepage, clicks over to the testimonials page and writes one of her own. To do so, she has to provide her email address (so we can send a thank-you email), and her testimonial. When she’s done composing her praise, she clicks the submit button and she’s done. What happens next? Since we don’t display new testimonials until they’re approved we should tell our happy customer that so she stays happy. The system also alerts the administrator that a new testimonial awaits approval. How that is done is not yet designed. Let’s put that on our to-do list.

Use Case 2: Jesse

Jesse had his portraits done at the studio too. He also is a happy satisfied customer. He also visits the website to write a blurb about his wonderful photo session. He clicks over to the testimonials page and reads a few that were previously submitted. He does not see Rachel’s testimonial since it has not yet been approved. The rest of this use case is the same as Rachel’s so let’s not repeat it here.

Use Case 3: Julie

Julie checks her email and finds two automated messages each informing her that Rachel and Jesse have left testimonials that are awaiting her approval. Included in each email is a live link to her website that takes her directly to a page that shows the new testimonials. From that page, Julie can review each testimonial and if she likes it she can approve it for publishing. She likes Rachel’s testimony and clicks her approval. A message is shown and highlighted on the page so that Julie is confident the system approved the testimonial. She then moves down the list, approving or rejecting the remaining testimonials.


So that’s our three main use cases. There isn’t much difference between Rachel’s and Jesse’s use case but it does highlight the fact that Jesse can’t see Rachel’s testimonial because it hasn’t been approved. Clearly, there’s more to the admin interface but we can leave that for later.

As discussed last time, we don’t have a model for our User…yet. Our user is pretty simple so we could just bang one out pretty easily, but why? One of the tenets of the Rails community is “don’t repeat yourself” (also known as keeping your code DRY). Well, I have another rule to add as a corollary: Don’t repeat others - Don’t reinvent the wheel unless you have a good reason… a very good reason. There’s a perfectly good user model out there for Rails and that’s acts_as_authenticated by Rick Olsen, a member of the Rails core team. It has a simple user model, supports account activation, and has quite a following of users. It’s not quite overkill for our use, but does future-proof our app in case Julie wants to delegate administration of the testimonials.Let’s get acts_as_authenticated installed now. It’s about as easy as it can get, first we tell rails where the source for the plugin lives, then install it by name:

# script/plugin source http://svn.techno-weenie.net/projects/plugins
# script/plugin install acts_as_authenticated

acts_as_authenticated is a generator, not a library. We’ll invoke it via the standard generate script (that was created for us by rails back in Part I) and generate both a model and a controller. Here, the model is user and the controller is account:

# script/generate authenticated user account
      exists  app/models/
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/account
      exists  test/functional/
      exists  test/unit/
      create  app/models/user.rb
      create  app/controllers/account_controller.rb
      create  lib/authenticated_system.rb
      create  lib/authenticated_test_helper.rb
      create  test/functional/account_controller_test.rb
      create  app/helpers/account_helper.rb
      create  test/unit/user_test.rb
      create  test/fixtures/users.yml
      create  app/views/account/index.rhtml
      create  app/views/account/login.rhtml
      create  app/views/account/signup.rhtml
      exists  db/migrate
      create  db/migrate/003_create_users.rb

Note that the generator created a migration for us; let’s run it:

# rake db:migrate
(in ~/webapps/testimony)
== CreateUsers: migrating =====================================================
-- create_table(\"users\", {:force=>true})
   -> 0.6846s
== CreateUsers: migrated (0.6849s) ============================================

We haven’t talked about unit testing yet, but we will. Let’s pretend that I didn’t forget about the tests for the testimonial_controller and notice that we have some fixture data in fixtures/testimonials.yml:

sasha:
  id: 1
  email: sasha@people.us
  testimony: \"this is sasha's testimonial\"
  approved: false
	
julien:
  id: 2
  email: julien@smith.com
  testimony: \"this is julien's testimonial\"
  approved: true

If you’re following along at home, you’ll have to edit test/functional/testimonial_controller_test and replace first with sasha so that the test uses the correct fixture data. At this point we haven’t added specific tests to our controller that test our new functionality, such as approving a post, but we’ll get to that later. We might even try a little test-driven development!
For now though, let’s run the tests we have and make sure everything works.

# rake
(in ~/webapps/testimony)
/usr/bin/ruby -Ilib:test \"~/gems/gems/rake-0.7.3/lib/rake/rake_test_loader.rb\" \"test/unit/user_test.rb\" \"test/unit/testimonial_test.rb\"
Loaded suite ~/gems/gems/rake-0.7.3/lib/rake/rake_test_loader
Started
...........
Finished in 0.237933 seconds.
	
11 tests, 18 assertions, 0 failures, 0 errors
/usr/bin/ruby -Ilib:test \"~/gems/gems/rake-0.7.3/lib/rake/rake_test_loader.rb\" \"test/functional/account_controller_test.rb\" \"test/functional/testimonial_controller_test.rb\"
Loaded suite ~/gems/gems/rake-0.7.3/lib/rake/rake_test_loader
Started
......................
Finished in 0.570801 seconds.
	
22 tests, 52 assertions, 0 failures, 0 errors
/usr/bin/ruby -Ilib:test \"~/gems/gems/rake-0.7.3/lib/rake/rake_test_loader.rb\"

Good! Everything passed. Notice that test were run for both the users and testimonial controllers.

That’s it for this installment. Next time, we’ll be adding some constraints to the models so Rails will do input validation for us, among other things.

Leave a Reply