Saturday, June 4, 2011

A little Saturday morning code jam

Here's my latest trouble with Manticore.

Eli showed me this code for a menu partial, which I put at the top of the Character view page. It allows you to switch to the view of a different model that belongs_to Character.

<%= link_to_unless_current 'Character', character_path(@character) %>
<%= link_to_unless_current 'Armor', character_armor_path(@character, @character.armor) %>


So this links to Armor's view page. Pretty awesome, except it doesn't work if Armor hasn't been built yet, which will be the case whenever creating a new character. Ops! I thought putting a method for creating a new instance of Armor if one didn't exist would fix this problem, but I couldn't get that to work, either. Also, I'm not convinced that's the best way to handle this problem. For another thing, I want to link to an Item page, not an Armor page, since I see Armor as being an Item.

I updated that code and here's what we've got now:

<%= link_to_unless_current 'Character', character_path(@character) %>
<%= link_to_unless_current 'Items', character_item_path(@character, @character.item) %>


However, this gives me a new error.

No route matches {:controller=>"items", :action=>"show", :id=>nil, :character_id=>#<Character id: 7, name: "Test" ... updated_at: "2011-06-04 15:43:59">


I'm not sure why I'm getting a routing error. Here's my route code:

resources :characters do
  resources :statistics
  ...
  resources :items
end


Here's what I'm trying to do with this menu partial. I'll want to have 5 links: Character, Items, Skills and Feats, Spells and Background. Much like the code David showed me for creating Statistics, I know I can use this method for all of them once I have it down.

And here's what I want the links to do. Clicking on Items will allow a user to create various types of items associated with that character: weapons, armor, pimp canes and so on. At this point I'm assuming Item will need to be a separate model, because it will have a belongs_to relationship with Character, right? Even though it's just going to be used as a view that displays forms for creating other models?

And Character should have a has_one relationship with Item, right? It's just going to be a single page, and while a Character can have many weapons, armors and pimp canes, I'll only be working with one Item view.

I'll have a day where everything I try to do works and I'm making great progress and I'll feel like the champion of code, then the next day I'll switch gears slightly and feel like I'm adrift on a hostile sea of errors. Anyone else have this same experience when you were learning Rails?

5 comments:

  1. That error shows that its going to items#show, but params[:id] is nil because that character has no item (this is one of your has_one relationships, right?).

    What you probably need to do is send you to items#new if @character.item is nil.

    <% if @character.item.present? %>
    <%= link_to_unless_current 'Items', character_item_path(@character, @character.item) %>
    <% else %>
    <%= link_to_unless_current 'Items', new_character_item_path(@character) %>
    <% end %>

    "If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime."

    The single best, and single worst thing about programming is that you constantly hit seemingly insurmountable obstacles...but then you eventually find your way around or through and dominate them. Its a wonderful feeling.

    ReplyDelete
  2. RE routing, for a belongs_to association and nested routes, I think you really want a singular resource [1], then the id is not necessary. In general we try not to use nested routes because they are often painful due to longer route names, required paramaters, etc. But in this case the nested routes should work out pretty nicely.

    [1] http://guides.rubyonrails.org/routing.html#singular-resources

    RE items, do singular items have behavior and state, or is it only the group of them? This is likely the deciding reason for single vs multiple items.

    For instance, in a gam we worked on, a user could have a few dozen different items, but each one he could have a huge number of (millions). Additionally, there was no state, like the wear of an item. In this case, having millions of rows for this data was quite wasteful, instead we had a single table that had dozens of integer columns relating to each of the different items with the integer meaning the number they had.

    If I was more familiar with DND I could probably give you better advice, you should seek out the advice of Sephonicus.

    ReplyDelete
  3. Oops, meant to say has_one instead of belongs_to.

    Also worth mentioning, we pre-created many has_one relationships on user creation. Meaning they were always there. Eventually we created has_one_autocreate to solve this problem but I doubt it works will Rails3!

    ReplyDelete
  4. @David Yeah, this is another has_one relationship. I tried the code you suggested, but now I'm getting this error:

    undefined method `item' for nil:NilClass

    I definitely agree with your quote. It's good to know this frustration never really goes away, though I suspect it gets easier to work around!

    ReplyDelete
  5. @Eli the thing with Item is I'm just wanting a page to display the items a character has. I figured creating a model and linking to its show page, the way you showed me to link to Armor's show page, would do the job.

    "RE items, do singular items have behavior and state, or is it only the group of them? This is likely the deciding reason for single vs multiple items."

    My thinking in making it a has_one relationship is simply because I just want to link to one Item show page, which will display several different models, of which a Character will have a has_many relationship: Armor, Weapons, etc. Does that make more sense? Might be easier to explain in person.

    ReplyDelete