POST vs. PUT

December 8th, 2005

Musicians will understand this analogy. Have you ever tried to learn a piece that goes the wrong way? That is, you’re playing along and it’s so obvious where the next notes are going to go and instead the piece goes off in a completely different direction. Half the time you find yourself playing the notes you think the piece should use rather than the notes it does use.

For me, understanding the difference between HTTP POST and PUT is very much like that. I’ve had a great deal of trouble understanding explicitly RESTful protocols like APP because they follow the actual definition of POST and PUT instead of what is to me clearly the right definition. However, I think I’m finally starting to get it.

My mistake is in thinking that anything that creates a new page is a PUT and anything that changes an existing page is a POST. In SQL terms, POST is an UPDATE and PUT is an INSERT. However, that’s not the case. In fact, the mistake is in trying to model PUT and POST in terms of INSERT and UPDATE. They really aren’t even close.

What actually happens is this. PUT puts a page at a specific URL. If there’s already a page there, it’s replaced in toto. If there’s no page there, a new one is created. This means it’s like a DELETE followed by an insert of a new record with the same primary key.

POST, however, really has no equivalent in SQL. POST sends some data to a specified URL. The server on the other end of this URL can do whatever it wants with this data. It can store it somewhere private. (HTTP 204 NO CONTENT). It can store it in the page at the URL that was POSTed to (HTTP 205 RESET CONTENT). It can store it in a new page, in which case it returns the URL of that page in the Location field of the HTTP response header (HTTP 201 CREATED). It can use it as input for several different existing and new pages. It can throw the information away. It can insert, update, or delete records in a database (or all of the above). It can start brewing coffee (HTTP 202 ACCEPTED). It can start global thermonuclear war. POST is decidely non-side-effect free and non-idempotent.

PUT is a much more limited operation that never does anything more than PUT one page at a specified URL. It is idempotent, which is a fancy way of saying that doing it twice is the same as doing it once. Both PUT and POST can be used to create new pages. However PUT should be used when the client specifies the location for the page. PUT is normally the right protocol for a web editor like DreamWeaver or BBEdit. POST is used when the client gives sends the page to the the server, and the server then tells the client where it put it. POST is normally the right protocol for a blog editor like TypePad or anything that inputs into a content management system. In SQL analogy, POST is an INSERT with an automatically generated primary key, and PUT is an INSERT that specifies the primary key in the INSERT statement.

Red-breasted Sparrow

December 7th, 2005

There’s no such thing as a Red-breasted Sparrow. There is, however, a female Eastern Towhee, which when you see it for the first time looks like nothing so much as a Red-Breasted Sparrow. However, if you look in your field guide for “Red-Breasted Sparrow” you won’t find it. If you keep looking a few pages past the sparrows, you’ll normally find the towhees though. But even that may not be enough.

To make matters even more confusing for the novice, the female Eastern Towhee does not in fact have a red breast. It has red flanks. However when you see it in the field, it’s often foraging on the ground so the breast is hidden. Consequently it ends up looking like a cross between an American Robin and a sparrow. Furthermore, the male Eastern Towhee doesn’t really look like a red-breasted sparrow at all, and some of the more basic field guides only show the male. So if you didn’t find Eastern Towhee in your field guide, or didn’t make the connection between the one in the book and the one in the field, you can now Google for “red-breasted sparrow” and find this page. How cool is that?

Spirit of 1999

December 6th, 2005

Wow. I haven’t seen an online store this bad in years. I know there are still a lot of crappy marketing sites out there, but most sites trying to immediately close sales long ago figured out that fancy tricks stop customers from buying. Not these folks.

It took me four or five tries to figure out where to click to see the page for the product I was interested in. On the third try I actually ended up on a page for a similar but slightly different and more expensive DVD burner than the one I was looking for. Initially I thought this was bait and switch, but one should never attribute to malice what can be explained by simple stupidity. I did eventually find the page for the product I wanted. Of course, this page promptly refused to sell me the drive because I didn’t have cookies turned on.

California “Adventure”

December 5th, 2005

Apparently not having learned from the Epcot disaster 20 years ago that tourists don’t want to educate themselves on their vacations, Disney has repeated their mistakes across the country at the new California Adventure theme park. Here you can pay the same price for half the rides, which include such thrilling excitements as watching bread bake! And if that isn’t exciting enough, you can go across the street and watch a different kind of bread bake! After which it’s only a short walk to the theatre where you can see a classroom filmstrip about the history of California! And then learn about California crops! If you’re all tuckered out from these exciting adventures, you might want to learn how to draw. Hard as it is to believe, I am not making this up. These really are “attractions” at California Adventure.

If after all this, you find yourself just too tired to ride one more ride, (more likely too tired to stand in one more line) you can sit in air conditioned comfort while watching an hour-long musical adaptation of a Disney movie. You’ve heard of straight-to-video movies? Aladdin: A Musical Spectacular is the stage equivalent: it skipped Broadway and the national tour to go straight to theme parks. The Lion King this isn’t. Heck, it’s not even Aida. Frankly I wouldn’t be surprised to learn the music and lyrics were written by the Orangeview Jr. High School band director, and performed by its drama club. (And if anyone from Orangeview Jr. High School is reading this, my apologies in advance for calumnying you that way. I’m sure you really are better than that.)

Of course I am picking on some of the most boring experiences there. There some nice touches too. The Tower of Terror is genuinely terrifying. Soaring Over California is a lot more exciting and fun than it sounds. It’s Hard to be a Bug is amusing; but that’s pretty much it. For the same $56 it costs to get into California Adventure, you could buy a one day pass to the Magic Kingdom with many more interesting rides to choose from.

Birding Geneva, Postscript

December 5th, 2005

Geneva’s not a large city or a hard city to get around in. You can reproduce most of this route simply by walking down to the lake, and then walking along either side, with side trips off into the various parks that line the lake. If you want to go a little further afield, the book to read is Les Bons Coins ornithologiques de Suisse Romande by the Groupe des Jeunes de Nos Oiseaux (Our Birds Youth Group). It provides detailed descriptions (in French) of over 100 excellent birding spots in the Southern part of Switzerland. It should be available in most large bookstores in Francophone Switzerland. Several of the chapters are online including la Rade de Genève et Petit Lac, which describes most of the route I took here. Even if you read French fairly well, it might still be helpful to carry a French field guide to assist with the bird names (Nettes rousse, Fuligules milouinans, Garrots, Macreuses, Harle huppé, etc.)

For actual identification of European birds, I’m partial to the Collins Bird Guide by Killian Mullarney, Lars Svensson, Dan Zetterström, and Peter J. Grant. It covers a larger area than I’d like ideally. (It’s a little annoying to think you’ve identified a bird only to check the map and discover the one you think you’re looking at only lives in Siberia or Israel.) However the pictures and text are second to none. It’s been translated into several languages, with adaptations for the countries that speak those languages. For instance, the English translation calculates bird rarity based on how likely birds are to be found in the British Isles. For field use make sure you order the paperback vesion, not the larger hardback version (though the latter has prettier pictures, it’s much too big to carry around in the field.)

The original Swedish version is Fägelguiden Europas och Mederhavsaomradets fägler i fält. Versions are also available in French, Dutch, German, Spanish, and possibly other languages.

Birds on Rails, Part 3

December 3rd, 2005

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.)

Currently Reading