Monday, May 9, 2011

This code is...problematic

It's been a while since my last blog post. Dang, a whole week! Don't worry, though. I never stopped coding.

I'm still having trouble with my Manticore app. Basically, here's what I'm trying to do:

I have two models, Character and Statistic. Each Character will have_one Statistic, and Statistic belongs_to Character. So good so far, right? I want to be able to create the Statistic information from the Character view, then be able to edit that information once there's information to be edited. I want to only be able to create one instance of Statistic per Character, hence the has_one relationship.

One solution I got on Stack Overflow was to simply make a form in the Character view, but since I'll be extrapolating this code (once I finally understand it) to create other models like Equipment, Skills, Spells and so on, it doesn't make sense to load down the Character view with a ton of different forms.

I've been modeling the code for Manticore from this tutorial which has you create a blog. It was easy enough to see that Character could be substituted for the Post model, and Statistic could be substituted for the Comment model.

However, I've hit a wall. Now I get this error:

undefined method `build' for nil:NilClass

And I'm not sure why. I suspect it has something to do with the has_one vs. has_many relationship. Earlier, I'd followed the tutorial more closely, but I need to define the Character/Statistic relationship as has_one vs. has_many because I don't need multiple instances of Statistics per character. Any ideas where this error could be coming from? I'm not defining a build action, but this error never popped up before.

Here's some code, if that helps:

class Character < ActiveRecord::Base  
  has_one :statistic, :dependent => :destroy
end

class Statistic < ActiveRecord::Base
  belongs_to :character
end

As far as I can tell, the model code is fine. But I might be missing something pretty obvious.

Here's code from the Statistics controller.

def create
  @character = Character.find(params[:character_id])
  @statistic = @character.statistics.create.new(params[:statistic])
  redirect_to character_path(@character)
end

I may have something wrong here, but like I said, this has worked in the past and has tied the Statistic to the specific Character (something I was struggling with before this mess!)

This is from the Statistics _form partial:

<%= form_for([@character, @character.statistic.build]) do |f| %>
  <div class="field">
    <%= f.label :strength %>
    <%= f.text_field :strength %>
  </div>
...
    <%= f.submit %>
  </div>
<% end %>

I suspect my troubles may be coming from this code, but I don't get why. I'm following the tutorial and this has worked before, and all I've changed is the has_many relationship to a has_one.

In other less concrete news, I feel pretty dumb for just not getting this. However, in the course of trying to figure it out, both on my own, through people I know and asking and reading questions on Stack Overflow, I've got a much better grip on other things, like the overall MVC hierarchy, how partials work, how views work and so on.

I think part of what's keeping me interested in Ruby and Rails is how difficult it is for me. Coding is not something I have a great natural talent for, so I really have to work to make progress. Still, I'm proud of what I've learned so far and there is no shortage of great, helpful people in addition to a treasure trove of information available, so I'm confident I'll get where I want to be. Sooner or later.

Another problem I've had is describing exactly what I want to do. I think in the future, I'll benefit greatly from mapping projects out better beforehand as well as learning how to describe my ideas better.