views:

488

answers:

3

I have a very annoying and hard to figure out bug in my rails project.

After having created a bunch of models and their relations, I want to list them.

But I keep getting an Error "can't dup NilClass". That is, until I restart the server. Then I can list them just fine.

Debugging this issue, it turns out that the Error gets raised in a method in one of the models when I try to return the value of one of its attributes. I have a breakpoint in the method, and this is what I get in the debugger:

    (rdb:5) self
    #<Bar id: 1037, foo: 2237, created_at: "2009-06-09 19:52:11", updated_at: "2009-06-09 19:52:47">
    (rdb:5) foo
    TypeError Exception: can't dup NilClass
    (rdb:5) attributes[:foo]
    nil
    (rdb:5) attributes["foo"]
    2237

I doesn't matter if I reload the page. I get the same error until I restart the server.

My model basically looks like this (the error occurs in method baz):

class FooBar < ActiveRecord::Base

    belongs_to  :foo, :class_name => "BarFoo", :foreign_key => "foo", :dependent => :destroy
    belongs_to  :bar, :class_name => "BarFoo", :foreign_key => "bar", :dependent => :destroy
    validates_presence_of :foo, :on => :create

    def baz
        [foo, bar].compact
    end
end

My schema looks like this:

create_table "foo_bar", :force => true do |t|
    t.integer  "foo"
    t.integer  "bar"
    t.datetime "created_at"
    t.datetime "updated_at"
end

Update:

Before I get any more answers pointing out that :foo and "foo" are not the same: I'm aware that they are not equal, but that is not the issue here.

And, I just confirmed that read_attribute("foo") does return the same as read_attribute(:foo). And so does self[:foo] and self["foo"]. None of these return nil. They do however all return the id of foo, instead of foo itself.

A: 

The difference is that you have a different key. In Ruby, :foo is not the same thing as "foo" (:foo is a symbol, while "foo" is a String).

You can try it out by putting :foo.to_s which will transform the symbol to a String if I'm not mistaken.

Jimmy Stenke
I'm well aware of this. It doesn't really address the problem, however.
KaptajnKold
+1  A: 

:foo is not equal to 'foo'. It is equal to 'foo'.to_sym or 'foo'.intern.

irb(main):001:0> hash = {:foo => 10, 'foo' => 'bar'}
=> {"foo"=>"bar", :foo=>10}
irb(main):002:0> hash[:foo]
=> 10
irb(main):003:0> hash['foo']
=> "bar"
irb(main):004:0> hash[:foo.to_s]
=> "bar"
irb(main):005:0> hash['foo'.to_sym]
=> 10
irb(main):006:0> hash['foo'.intern]
=> 10
Pesto
+1  A: 

Finally solved it!

Although I'm not exactly sure why, the problem goes away if I add "unloadable" to the model definition:

class FooBar < ActiveRecord::Base

    unloadable

    belongs_to  :foo, :class_name => "BarFoo", :foreign_key => "foo", :dependent => :destroy
    belongs_to  :bar, :class_name => "BarFoo", :foreign_key => "bar", :dependent => :destroy
    validates_presence_of :foo, :on => :create

    def baz
        [foo, bar].compact
    end
end

This site is where I found the solution. I totally do not understand it, but it works :-)

KaptajnKold