Archive for the ‘Resources’ Category

At Home With Nested Routes and Resources

Tuesday, April 6th, 2010

When I first heard about nested routes, as with most things in Rails, I completely ignored them, discounting them as something I’d get to learning when I needed to, but right now they were yet another one of those things that I didn’t quite grok as I didn’t have the other base knowledge of the Rails system to know why I needed them. To be fair, I’m not that much closer now, and started to realize the the other day I didn’t really quite understand REST and having a RESTful site.

But when I started looking at how my site was structured, and how things were really encapsulated in each other, such as clubs “having” fields, and fields “having” games, I started to understand the need. Actually it was more doing the scaffolding of the site and seeing that I had to set field in a dropdown each time I created a game, or the club each time I created a field. It didn’t make sense and it seemed like a stupid way to do it.

Back in the old days in perl, I’d pass the ID of the main object when I created a sub-object. So if I had a club editing page with a ‘create new field’ button on it, that button would pass a hidden “club_id=$id” when it was pressed.

Rails comes with a nicer way of doing it. It allows you to nest related resources. Probably the best place to start is with Ryan Bates excellent Nested Resources screencast, or Adam’s Nested Resources in Rails 2 page.

For this I set up the following in my routes.rb as such:

map.resources :clubs, :has_many => :areas, :shallow => true

And then running “rake routes” will show you what the routes will actually be:

     club_areas GET    /clubs/:club_id/areas(.:format)            {:action=>"index", :controller=>"areas"}
                POST   /clubs/:club_id/areas(.:format)            {:action=>"create", :controller=>"areas"}
  new_club_area GET    /clubs/:club_id/areas/new(.:format)        {:action=>"new", :controller=>"areas"}
          clubs GET    /clubs(.:format)                           {:action=>"index", :controller=>"clubs"}
                POST   /clubs(.:format)                           {:action=>"create", :controller=>"clubs"}
       new_club GET    /clubs/new(.:format)                       {:action=>"new", :controller=>"clubs"}
      edit_club GET    /clubs/:id/edit(.:format)                  {:action=>"edit", :controller=>"clubs"}
           club GET    /clubs/:id(.:format)                       {:action=>"show", :controller=>"clubs"}
                PUT    /clubs/:id(.:format)                       {:action=>"update", :controller=>"clubs"}
                DELETE /clubs/:id(.:format)                       {:action=>"destroy", :controller=>"clubs"}

The biggest, biggest thing to notice here is the “:id” and “:club_id” in some of the routes. This tripped me up a few times.

Nested routes let you automagically pass “club_id” (in this case) to paths. So in your controller or views you can now use the variable from the first column. So you can do a

redirect_to clubs_path
# instead of:
redirect_to :controller => "clubs", :action => "index"

for example, and it would go to the /clubs/index path and do the right thing. It also lets you do things like:

redirect_to new_club_area(@club)
# sends you to /clubs/1/areas/new

Note that you have to pass the club before this will work. This took me forever to figure out, cause sometimes it worked and sometimes it didn’t. What I found was looking for either :id or :[object]_id in the routes path would tell you both if you have to pass the route the object or not, but also if you’re processing the path in the controller, that :club_id will be passed auto-magically to it. So for the “/clubs/:club_id/areas/new” route above, you’d process it in your areas_controller, and in the ‘new’ def, you’d automatically get club_id for free. IE:

# in app/controllers/area_controller.rb, possibly via new_club_area_path(@club)
def new
   @club = Club.find(params[:club_id])
   @area = @club.areas.new
end

You know that club_id is being passed because the rake_route for that path has “club_id” in it: “/clubs/:club_id/areas/new”.

Next up, finishing converting as much of the rest of my code from the controller/action syntax for redirecting and rendering to a more “restful” setup.

Update: There is a cool sounding TextMate bundle to help you with some of the brain games needed to understand nested resources.  Hat tip to The Ruby Show.

Discovering Ruby With Ruby Warrior

Thursday, May 14th, 2009
Code from Level 6

Code from Level 6

Thanks to the FV.rb last night I discovered Ruby Warrior, a neat and fun way of learning ruby.  It goes like this….

First, head to http://github.com/ryanb/ruby-warrior/tree/master and download the tree by using “git clone“, then simply run “bin/rubywarrior” out of the main ruby-warrior directory that the git clone command creates.  The first run will create a profile and set up the initial part of the “game”.

The “game” is a bit like the old adventure text games, with a simple ASCII “dungeon” that you see your guy move through, and as the levels progress you will encounter monsters, harder monsters, captives to rescue, and so on as you move from one side of the dungeon to the stairs on the other side.  The system is turn based, so you are basically creating yourself a little state machine.  You basically check to see if there’s something in front of you and if not walk, if it’s an enemy, attack, etc.

To do this you end up doing something like this:

  1. You look at the README file in the ruby-warrior/beginner-tower/level-001/ directory.  You may have “intermediate-tower” instead of beginner depending on the level you chose during the initial setup.
  2. Follow what the README file says and edit the file ruby-warrior/beginner-tower/level-001/player.rb adding code to make your warrior move and fight.
  3. Run bin/rubywarrior and see how well your warrior moves and fights.  It will either succeed and allow you to continue to the next level (in which case go to step 1, substituting the right number in the “level-00N” directory), or you will fail, in which case, re-edit the warrior.rb file and try again.

The game isn’t for complete and total programming n00bs, but might be a bit simple for people who know programming, but not ruby :)   It starts out with simple commands and simple if/then/else control structures.  However, it does make it cool and interesting enough that it has kept my interest for at least until now.

Rails Resources

Sunday, May 3rd, 2009

As with all noobie learners, one of the best ways to learn about Ruby and Rails is to read sites on the net.  This has it’s good sides and bad sides.  On the good side, there’s a vast amount of information out there, free for the taking.  People are willing to throw out information about coding skills, projects, give you access to their source code…. all for free.  On the bad side, it’s the wild west.  There’s scads of information, mostly unsorted, and a lot of the people sharing it are on the edge of the technology, and it’s very easy to get lost in the latest-and-greatest and completely miss learning the simple and fundamental lessons.

To quote a game programming book I read once long ago: “First make it work, then make it work fast.”  It’s fairly easy to move that to the ruby world.  “First write a rails app, then write one with the latest wiz-bang plugin.”  OK, maybe it doesn’t work that well :)

Here’s a list of some of the sites I keep in my RSS reader for keeping up to date…

(more…)