2008-01-01

Alright, here we go. I'm going to just walk through implementing STI and record what I run into here.

I have a table called Tasks. This will represent a schedule item of work that needs to be done. For reasons I may describe later, I'm planning to sublclass Task into classes like PhonecallTask and SendemailTask.

Thus far I've:
  • created a migration that ensures I have a "class" (was type before) column in my tasks table
  • created two new files in my app/models directory: phonecall_task.rb and sendemail_task.rb
  • opened a console
>> t = Task.new({:class => 'PhonecallTask'})
=> #nil, "class"=>"PhonecallTask"}, @new_record=true>
>> t.class
=> Task
>> PhonecallTask.find(:first).class
=> PhonecallTask
>> Task.find(:first).class
=> Task
From this I find that Rails is, at least partially, correctly interpreting my use of the "class" column. Also I note that a given class's find method returns instances of that class - I may want to change this later if possible.
When I try to instantiate PhonecallTask it seems to work fine:

>> pt = PhonecallTask.new
=> #nil, "class"=>nil}, @new_record=true>

But for SendemailTask I get the following error:

>> st = SendemailTask.new LoadError: Expected script/../config/../config/../app/models/sendemail_task.rb to define SendemailTask from ./script/../config/../config/../vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:250:in `load_missing_constant' from ./script/../config/../config/../vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:453:in `const_missing' from ./script/../config/../config/../vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:465:in `const_missing' from (irb):2

At first I think this may be the problem described at rails wiki, about Rails having to be aware of them models before they can be worked with. But a closer look reveals I just forgot to put a class definition in sendemail_task.rb . Here is my class definition:

class SendemailTask < style="color: rgb(0, 0, 153);">end


--------------------

N
ow I'm running into a new problem: when trying to run an object method (not a class method) on an object whose class is a subclass of Task, I get an "undefined method" error. So I have a method defined for Task called 'parameters'. It returns a hash built from a value stored in the database called 'stringified_parameters'. When I try to run this on SendemailTask, it gives me an "unefined method" error.

....

The text ended at this point. There was no explanation of the resolution of the error, if any was found. Michael Crichton shifted his reading glasses up and down his nose for a second - it was an unconscious habit of his; it helped him think. At least he thought it did. Anyway, his nose itched.

He had a hunch there was more to the story that didn't appear in the log. That was how Luke usually worked: starting carefully, recording everything in high detail at the outset, then diving in headfirst and getting ahead of himself - and whatever notes he was taking.

But something nagged at him. Michael knew Luke had been briefed in the protocols for situations like this; surely he had read Michael's report of the incident in Nevada ... trusting a hunch he scrolled down the page ...

Bingo. After an oddly out-of-place narrative section, there was a terse and halfhearted conclusion:

-------------------------------------------------------------

Long story short, after the preceding notes were taken I switched from using the word "class" back to using the word "type", because despite the warning messages from within Rails, 'type' was not deprecated, and it wouldn't do anything if I used the word 'class'.

Eventually, no matter how many places I attempted to put include statements telling Rails that my subclass models were there, it refused to recognize the existence of any object methods. At first I thought my subclasses weren't inheriting the methods. Then I wrote in the subclass method definitions of the same name and just called super. Then I tried just instantiating the superclass and calling the method from there. It was all for naught, though. Any time I called any object method it was "undefined method this_method_most_definitely_exists for class YourSubclass".

The only thing I was missing was putting 'require_dependency' or 'model' (depending on which blog you read) in the ApplicationController. When I tried this (which is the only thing everyone in the blogosphere agrees on - that I should do this) I got the dreaded "We're sorry, but something went wrong. We've been notified and will ... wait, no we haven't, because we're the developer and we're looking at the most opaque error message ever created. Thanks Rails". I'm really not so bitter. I used an ugly hack to do what I need to do and I've moved on.

..


..












No comments: