Forum: Ruby on Rails some strange behavior for has_many with STI

Announcement (2017-05-07): is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see and for other Rails- und Ruby-related community platforms.
5d74875357814b1d2bad37f7498bd244?d=identicon&s=25 Joshua Cohen (Guest)
on 2006-03-19 12:17
(Received via mailing list)
Hi all,

I'm having some trouble with a has_many association on a table using
the single table inheritance model that I'm hoping someone can help me
with.  The schema for the table is:

CREATE TABLE `comments` (
  `id` int(11) NOT NULL auto_increment,
  `user_id` int(11) default NULL,
  `type` varchar(20) NOT NULL default '',
  `type_id` int(11) NOT NULL default '0',
  `name` varchar(255) default NULL,
  `comment` text NOT NULL,
  `created_at` datetime default NULL,
  `updated_at` datetime default NULL,
  PRIMARY KEY  (`id`),
  KEY `FK_users_comments` (`user_id`)

ALTER TABLE `comments`
  ADD FOREIGN KEY (`user_id`) REFERENCES `users` (`id`);

on top of which, I've got two tables: events and activities, both of
which can have comments.  Here are the model associations for Events,
Activities and Comments:

class Activity < ActiveRecord::Base
  belongs_to :user
  has_many :comments, :conditions => "type = 'Activity'", :foreign_key
=> "type_id"
  acts_as_taggable :join_class_name => "TagActivity"

class Event < ActiveRecord::Base
  include EventMatching
  belongs_to :activity_type
  has_and_belongs_to_many :users
  has_many :comments, :conditions => "type = 'Event'", :foreign_key =>

class Comment < ActiveRecord::Base
  belongs_to :user
  belongs_to :activity, :conditions => "type = 'Activity'",
:foreign_key => "type_id"
  belongs_to :event, :conditions => "type = 'Event'", :foreign_key =>

The strange behaviour is this: for activities, everything works
perfectly.  I can do:

render(:partial => "shared/comment", :collection => @activity.comments)

And it works like a charm.  When I do the same for events:

render(:partial => "shared/comment", :collection => @event.comments)

I get an error: undefined method `user' for #<Event:0x382e3a8>.  This
error is on the first line that accesses comment.user in the partial.

Here is the SQL I'm seeing in the development.log for fetching
comments for Activities and Events:

SELECT * FROM comments WHERE (comments.type_id = 59 AND (type =
SELECT * FROM comments WHERE (comments.type_id = 8 AND (type = 'Event'))

Both queries return the correct rows when executed directly against
the DB (MySQL 5 btw).  The really odd thing though, is if I comment
out the belongs_to :user from the Activity model, then Activity starts
throwing the same error as Event.  Somehow it looks like the
association from Comment to User is relying upon the parent object
also having an association to user (even though Event does have a
h_a_b_t_m :users, it's still breaking), and even though the Comment is
relying on the parent's relationship, it's still pulling in the proper
user for each individual comment.

This has had me stumped for the better part of the day, so hopefully
someone might have some insight.  If there's any relevant info or code
I've left out let me know and I'll be glad to share it.

Thanks in advance,

631d1677786f0725da6ccee46043686e?d=identicon&s=25 Jonathan Viney (Guest)
on 2006-03-19 12:17
(Received via mailing list)
That's not quite how STI is supposed to be used. What you should do is
something like:

class Comment < ActiveRecord::Base

class EventComment < Comment

class ActivityComment < Comment

class Event < ActiveRecord::Base
  has_many :comments, :class_name => 'EventComment'

class Activity < ActiveRecord::Base
  has_many :comments, :class_name => 'ActivityComment'

Throw an event_comment_id and activity_comment_id on the comments table,
remove type_id.

Haven't tried it but it should do what you're after.

The user error you are getting is because there is no 'user' association
Event. You have used a belongs_to on Activity, and
on Event. You need to access Event.users instead.

This topic is locked and can not be replied to.