views:

984

answers:

6

I'm trying to setup single table inheritance in my Rails app for a User model and its subclasses Member, Subscriber, and Staff.

I have a model file for each: user.rb, member.rb, etc

The user model is defined: class User < ActiveRecord::Base; end; I subclassed the other models as such: class Member < User; end; and so on.

In my users table I have all the fields every class needs plus the type field. Now when I go to the console and try to create a new instance of say member or subscriber i get the following error:

TypeError: can't dup NilClass from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2184:in 'dup' from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2184:in 'scoped_methods' from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2188:in 'current_scoped_methods' from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2171:in 'scoped?' from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2439:in 'send' from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2439:in 'initialize' from (irb):6:in 'new' from (irb):6

Rails know the subclasses models are there because in the console when I simply call Member or Subscriber, i get the class definition returned.

I've read the simple documentation, but I must be missing something?

A: 

Hello,

I tried on my side starting from a scratch application and it works

Here is my User model (User.rb)

class User < ActiveRecord::Base
end

My member model (Member.rb)

class Member < User
end

I have one migration file to create my users table which contains:

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :name
      t.timestamps
    end
  end

  def self.down
    drop_table :users
  end
end

Now launching the console:

➜  ./script/console     
Loading development environment (Rails 2.3.4)
>> u = User.new
=> #<User id: nil, name: nil, created_at: nil, updated_at: nil>
>> m = Member.new
=> #<Member id: nil, name: nil, created_at: nil, updated_at: nil>
>> m.name="hop"
=> "hop"
>> m.save
=> true

However I did not manage to reproduce your error :(

Aurélien Bottazzini
Your migration is missing the `:type` attribute that STI needs to work properly.
Matt Haley
+1  A: 

Do you have a type column of type varchar (string in ruby)? Try the following commands (in a new rails project)

class Member < User
end

C:\projects\test\sti>ruby script\generate model user name:string type:string membertype:string
  exists  app/models/
  exists  test/unit/
  exists  test/fixtures/
  create  app/models/user.rb
  create  test/unit/user_test.rb
  create  test/fixtures/users.yml
  create  db/migrate
  create  db/migrate/20091019051506_create_users.rb

C:\projects\test\sti>rake db:migrate
(in C:/projects/test/sti)
==  CreateUsers: migrating ====================================================
-- create_table(:users)
   -> 0.0000s
==  CreateUsers: migrated (0.0000s) ===========================================


C:\projects\test\sti>ruby script\console
Loading development environment (Rails 2.3.4)
>> u = User.new
=> #<User id: nil, name: nil, type: nil, membertype: nil, created_at: nil, updated_at: nil>
>> m = Member.new
=> #<Member id: nil, name: nil, type: "Member", membertype: nil, created_at: nil, updated_at: nil>
>> m.name = 'fred'
=> "fred"
>> m.save
=> true
>> u.name = 'rader'
=> "rader"
>> u.save
=> true
>> User.find :all
=> [#<Member id: 1, name: "fred", type: "Member", membertype: nil, created_at: "2009-10-19 05:17:11", updated_at: "2009-10-19 05:17:11">, #<User id: 2, name: "rader", type: nil, membertype: nil, created_at: "2009-10-19 05:17:24", updated_at: "2009-10-19 05:17:24">]
>>
spirc
You need to add a special column 'type' which is what ActiveRecord uses to track subclassed models in a single table.
Nicholas C
A: 

I'm thinking that the problem is in one of your model definitions because of the stack trace you show. If you still are having a problem, pastie your code, and i'm sure you'll get a good answer.

A: 

I hade exactly this problem, after I extracted some functionality to a plugin.

But i my case it worked from the console, so i made sure id reloaded, with this line in init.rb ActiveSupport::Dependencies.load_once_paths.delete( File.expand_path(File.dirname(__FILE__))+'/app/models')

jnstq
A: 

I ran into something similar a while back and this website helped:

http://www.dansketcher.com/2009/05/11/cant-dup-nilclass/

class User < ActiveRecord::Base
  unloadable

  ...
end

Not sure why this occurs as I could not track down anything abnormal. I do believe it was a STI situation though.

Alan Peabody
A: 

Check this page, there are more than few solutions to this problem (even in comments).

http://strd6.com/2009/04/cant-dup-nilclass-maybe-try-unloadable/

sharas