STI subclassing

Hi, all. I'm wrestling with subclassing models in AR. Wondering if i'm
running up against a limitation on sub-subclassing, or if the syntax
has gone awry here.

My app has BlogPosts, which are a sub of Articles. It's got Writers <
RegisteredUsers < Users.

When I try to call registered_user on a BlogPost, I get nil.

Any & all help appreciated.

class Article < ActiveRecord::Base
  etc....

end

class BlogPost < Article
  validates_presence_of :section_id, :title, :body
  belongs_to :registered_user

end

class NewsArticle < Article
belongs_to :writer
end

require "digest/md5"
class User < ActiveRecord::Base
etc...
end

class RegisteredUser < User
   validates_uniqueness_of :name
   has_many :comments
   has_many :events, :class_name => "Article", :foreign_key =>
"user_id"
   has_many :blog_posts, :class_name => "Article", :foreign_key =>
"user_id"
end

class Writer < RegisteredUser
  has_many :news_articles, :class_name => "Article", :foreign_key =>
"user_id"
end

@post=BlogPost.find(:first, :conditions=>'user_id=1')

=> #<BlogPost id: 505, title: "Cubs outlook", type: "BlogPost",
user_id: 1>

User.find(1)

=> #<Writer id: 1, type: "Writer">

@post.registered_user

=> nil

magic_hat wrote:

My app has BlogPosts, which are a sub of Articles. It's got Writers <
RegisteredUsers < Users.

When I try to call registered_user on a BlogPost, I get nil.

Any & all help appreciated.

class Article < ActiveRecord::Base
  etc....

end

class BlogPost < Article
  validates_presence_of :section_id, :title, :body
  belongs_to :registered_user

end

class NewsArticle < Article
belongs_to :writer
end

require "digest/md5"
class User < ActiveRecord::Base
etc...
end

class RegisteredUser < User
   validates_uniqueness_of :name
   has_many :comments
   has_many :events, :class_name => "Article", :foreign_key =>
"user_id"
   has_many :blog_posts, :class_name => "Article", :foreign_key =>
"user_id"
end

class Writer < RegisteredUser
  has_many :news_articles, :class_name => "Article", :foreign_key =>
"user_id"
end

@post=BlogPost.find(:first, :conditions=>'user_id=1')

=> #<BlogPost id: 505, title: "Cubs outlook", type: "BlogPost",
user_id: 1>

User.find(1)

=> #<Writer id: 1, type: "Writer">

@post.registered_user

=> nil

You should instead have:

belongs_to :registered_user, :foreign_key => :user_id

A Rails bug meant that you didn't get an error message.

That works. Thanks.

One other issue that's cropping up.

The STI inheiritance has some weird loading behavior. Writers are not
found with RegisteredUser.find until after they've been loaded with
Writer.find:

RegisteredUser.find_by_name('John Doe')

=> nil

Writer.find_by_name('John Doe')

=> #<Writer id: 1, name: "John Doe">

RegisteredUser.find_by_name('John Doe')

=> #<Writer id: 1, name: "John Doe">

Any idea what that's all about?

magic_hat wrote:

The STI inheiritance has some weird loading behavior. Writers are not
found with RegisteredUser.find until after they've been loaded with
Writer.find:

RegisteredUser.find_by_name('John Doe')

=> nil

Writer.find_by_name('John Doe')

=> #<Writer id: 1, name: "John Doe">

RegisteredUser.find_by_name('John Doe')

=> #<Writer id: 1, name: "John Doe">

Any idea what that's all about?

Yes, STI subclasses aren't added to find conditions
until they're loaded.

One way to force loading of subclasses is to call
require_dependency at the bottom of model files.
e.g. require_dependency 'writer'.

Another way is to name each leaf STI class in
environment.rb, which forces loading of all classes
up the tree.

You may have to use method 2 for production mode
and method 1 for other modes.

There's also this plugin, which I haven't yet tried:
   http://agilewebdevelopment.com/plugins/has_types