Birds on Rails, Part 3

Now I want to create a new page that lists all the species in the birds table. That is, it looks like this:

Brooklyn Bird Report Master Bird List

  • Fulvous Whistling-Duck Dendrocygna bicolor
  • Greater White-fronted Goose Anser albifrons
  • Snow Goose Chen caerulescens
  • Ross’s Goose Chen rossii
  • Brant Branta bernicla

This will live in the file /masterbirdlist.rhtml

How to do it? I begin by creating a regular HTML file named masterbirdlist.rhtml and putting it in the app/views/bbr directory, but that doesn’t work. It just tells me “Unknown action No action responded to masterbirdlist.rhtml.” OK. Looking back at the notes from Day 1, I see how to handle that. I add this method to the bbr_controller.rb file:

def masterbirdlist
  render_text "Hello"
end

Now I get “Hello” for the masterbirdlist. Of course that’s not what I want. I want to load the masterbirdlist.rhtml file. How do I do that? About this point I begin wondering what the manual says. Googling for it, it appears that there isn’t one. That compares very unfavorably with PHP and Java, both of which at least have documentation, not to mention reams of third party books available. (Later I found this site, but it doesn’t appear to be a true comprehensive manual; just a random collection of HowTos.) However, there does seem to be some API documentation which mentions render_file() methods. Maybe that’s what I need? No wait. I remember this now. I bet I have to generate a controller for the masterbirdlist:

~/Web sites/bbr$ script/generate controller masterbirdlist
      exists  app/controllers/
      exists  app/helpers/
      exists  app/views/masterbirdlist
      exists  test/functional/
   identical  app/controllers/masterbirdlist_controller.rb
   identical  test/functional/masterbirdlist_controller_test.rb
   identical  app/helpers/masterbirdlist_helper.rb

That seems to work. I thought this was just for mapping to database tables, but apparently it’s for all pages. This gives me the “Unknown action No action responded to index” at /masterbirdlist. But I’ll create a view for this in app/views/masterbirdlist/index.rhtml. Bingo! That works.

Now let’s add the code to generate the list of species:

<ul>

 <% @birds.each do |bird| %>
  <li><%= bird.common_name %></li>
 <% end %>
</ul>

This produces

NoMethodError in
Masterbirdlist#index

Showing app/views/masterbirdlist/index.rhtml where line #14 raised:

You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occured while evaluating nil.each

So now I have to create the birds variable. Thus I add this code to the masterbirdlist_controller.rb:

def index
  @birds = Bird.find_all
end

Now I get this error:

NameError in
Masterbirdlist#index

uninitialized constant Bird

I suspect this is because I haven’t mapped that table in Rails yet. i.e. I haven’t generated a model for the birds. Let’s do that:

$ script/generate model Bird
      exists  app/models/
      exists  test/unit/
      exists  test/fixtures/
      create  app/models/bird.rb
      create  test/unit/bird_test.rb
      create  test/fixtures/birds.yml

And now the page works. OK. I ‘m starting to get the hang of this. Adding the genus to the list is easy:

<% @birds.each do |bird| %>
  <li><%= bird.common_name %>  <i><%= bird.genus %></i></li>
 <% end %>

Now let’s add the species:

 <% @birds.each do |bird| %>
  <li><%= bird.common_name %>  <i><%= bird.genus bird.species %></i></li>
 <% end %>

Oops. That didn’t work:

ArgumentError in
Masterbirdlist#index

Showing app/views/masterbirdlist/index.rhtml where line #15 raised:

wrong number of arguments (1 for 0)

Hmm. Do I just need to put that in two separate tags or do I need to learn how to concatenate strings or terminate statements in Ruby? Concatenating seems to work; and it uses the plus sign, same as in Java:

 <% @birds.each do |bird| %>
  <li><%= bird.common_name %>  <i><%= bird.genus + bird.species %></i></li>
 <% end %>

However, it turns out I forgot a space, so I might as well just go ahead and use two tags anyway:

 <% @birds.each do |bird| %>
  <li><%= bird.common_name %>  <i><%= bird.genus %> <= bird.species %></i></li>
 <% end %>

I think that’s as far as I’m going to go tonight, but just maybe I am speeding up a little past what I could do with PHP (though I still don’t fully grok how the site is getting organized, and the URLs mapped.)

5 Responses to “Birds on Rails, Part 3”

  1. George Bailey Says:

    This is great. You’re like a Jerry Pournelle with skills. I think you should throw in there somewhere “remember, I go through this so you don’t have to.” ;-)

  2. raichu Says:

    wow. so this is ruby on rails “power learning”. no simple tutorials or sample cookbook applications here; just straight on porting an existing project, tacking on accumulated info about the framework as you go on. not even a hint of rails’ “scaffolding” or that weird article “rails – what goes where” by amy hoy (http://slash7.com/articles/2005/03/06/rails-what-goes-where). not even a ruby syntax tutorial on statement termination and string concatenation! no questions, no documentation, no pauses; just a wild ride on intuition, convention, and how-many-years of programming experience.

    i’m currently doing the same thing with the python web framework turbogears and the java web framework wicket. i can really relate; wicket has so little documentation that i can only hope i’m not reinventing anything like PageableOrderedListViews right now. i have a lot of headaches nowadays but i love the learning experience all the same.

    btw, you wrote in your initial code <% bird.genus bird.species %>, which gave you an error. in ruby, parentheses are optional; instead of concatenating the two as you intended, you actually called the method bird.genus with the parameter bird.species. it’s equivalent would be bird.genus( bird.species ) in java. For example, whereas in java the syntax for a method would look like overlay.layout( Point center, Double radius ), the syntax in ruby would look like overlay.layout center, radius.

    the default layout of the files, when the scaffolding tool is used, mirrors the actions for that model. for instance, if you have a set of birds, their controller would be called birds_controller, and it would have a model class called birds.

    if i want a web page that lists a bunch of birds, i can find the code in the list method of BirdsController, the class of which can be found in app/controllers/birds_controller.rb i would then look for the list.rhtml page in app/views/birds directory. if i want a web page that edits the bird’s info, i can find the code in the edit method of BirdsController, the class of which can be found in app/controllers/birds_controller.rb i would then look for the edit.rhtml page in app/views/birds directory. amy hoy’s cheatsheet can probably explain it better than i can (http://slash7.com/cheats/rails_files_cheatsheet.pdf).

    if i were in your shoes and i wanted the default (scaffolded) way of displaying bird info, i would run “script/generate scaffold birds”. i would then go to the created app/controllers/birds_controller.rb file and make sure that its list method has the line @birds = Birds.find_all (or maybe write that list method myself). then i would open the file app/views/birds/list.rhtml and write my display code there, probably something similar to what you wrote.

    i find rails restrictions on the placement and naming of files to be real draconian. i find it tolerable because it’s much like java’s package com.foo.bar; java expects the public com.foo.bar.SomeClass to be placed in a file called SomeClass.java under the directory com/foo/bar. at times, ruby on rails philosophy seems like some weird version of some social contract: “give up your naming conventions and method idiosyncracies and rails will make your life easier. do something that isn’t our way and we’ll hand you over to the mafia.”

  3. Marcus Says:

    Hi,

    thank you for writing down your approach to handle Ruby on Rails. I just reached a point with a similar problem and you gave me the right hint.

    greetings

    mtk

  4. akuma624 Says:

    Dude,

    Your insightful explanation of the list view error when designating a specific view based on the table columns – saved my life.

    Its people like you that make the net a indespensible tool for everyone.

    Please posting on your great work and thanks again.

  5. home slot machine Says:

    home slot machine…

    explore.Poole!inscribing?confine …

Leave a Reply