# Polymorphic STI with associations

**URL:** <https://www.ruby-forum.com/t/polymorphic-sti-with-associations/175627>\
**Category:** Rails\
**Created:** [September 16, 2009, 7:54pm UTC](https://www.ruby-forum.com/t/polymorphic-sti-with-associations/175627 "2009-09-16T19:54:48Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![eric](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/898d66/32.png) [@eric](https://www.ruby-forum.com/u/eric)\
**Post date:** [September 16, 2009, 7:54pm UTC](https://www.ruby-forum.com/t/polymorphic-sti-with-associations/175627/1 "2009-09-16T19:54:48Z")

</div>

I have been working on a polymorphic STI schema where the inheriting  
classes have associations:

class Asset \< ActiveRecord::Base  
end

class Sound \< Asset  
belongs\_to :user, :polymorphic =\> true  
end

class User \< ActiveRecord::Base  
has\_many :sounds  
end

The Asset class contains a ‘type’ attribute which is getting properly  
populated with the inheriting class’s name, so that’s fine, but I was  
getting an error that there was no ‘user\_type’:

undefined method `user\_type’ for #Sound:0x4cf3740

OK, so I added ‘user\_type’ to the Asset model and I can get past that  
error (which was only raised upon a :destroy for the object). However,  
now that I’ve added it, the user\_type is not being populated when new  
objects are created/saved. Am I missing something?

-eric

---

<div class="post-metadata">

**Author:** ![eric](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/898d66/32.png) [@eric](https://www.ruby-forum.com/u/eric)\
**Post date:** [September 17, 2009, 6:31pm UTC](https://www.ruby-forum.com/t/polymorphic-sti-with-associations/175627/2 "2009-09-17T18:31:44Z")

</div>

On Sep 16, 1:52 pm, Eric [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> class User \< ActiveRecord::Base  
> error (which was only raised upon a :destroy for the object). However,  
> now that I’ve added it, the user\_type is not being populated when new  
> objects are created/saved. Am I missing something?

The :polymorphic and the user\_type field aren’t necessary -  
polymorphic associations are used when you’ve got objects from  
multiple tables that all might be associated to a record, eg:

class Foo \< AR::Base  
belongs\_to :things, :polymorphic =\> true  
end

class ThingA \< AR::Base  
has\_many :foos, :as =\> :thing  
end

class ThingB \< AR::Base  
has\_many :foos, :as =\> :thing  
end

Note that ThingA and ThingB are in seperate tables - if they were  
related via STI the :polymorphic wouldn’t be needed.

–Matt J.

---

<div class="post-metadata">

**Author:** ![eric](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/898d66/32.png) [@eric](https://www.ruby-forum.com/u/eric)\
**Post date:** [September 17, 2009, 8:12pm UTC](https://www.ruby-forum.com/t/polymorphic-sti-with-associations/175627/3 "2009-09-17T20:12:25Z")

</div>

On Sep 17, 8:44 am, Matt J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > end
> 
> belongs\_to :things, :polymorphic =\> true  
> Note that ThingA and ThingB are in seperate tables - if they were  
> related via STI the :polymorphic wouldn’t be needed.

Thanks for the reply, and I did leave a part out of my schema. There  
will be other models inheriting from Asset, such that ultimately there  
will be (at least):

class Asset \< ActiveRecord::Base  
end

class Sound \< Asset  
belongs\_to :user, :polymorphic =\> true  
end

class Video \< Asset  
belongs\_to :user, :polymorphic =\> true  
end

class Image \< Asset  
belongs\_to :user, :polymorphic =\> true  
end

class User \< ActiveRecord::Base  
has\_many [:sounds,:videos,:images]  
end

The idea will be to have @user.videos, @user.images, etc., so the STI  
will handle the media types, and the polymorphism is used for User’s  
relationship to each. However, currently user\_id is not being saved  
through the association, and even if I manually set user\_id in Asset  
(and user\_type, just for fun), Video.first.user comes up nil. So, STI  
is working as expected, but the association is broken in some way that  
leads me to wonder whether Asset needs some connection with User  
(unlikely, given the docs and commentary I’ve been able to find), or  
whether the STI classes need some more connections to the base class  
in order for User to pass through the STI.

-eric

---

<div class="post-metadata">

**Author:** ![eric](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/898d66/32.png) [@eric](https://www.ruby-forum.com/u/eric)\
**Post date:** [September 17, 2009, 10:27pm UTC](https://www.ruby-forum.com/t/polymorphic-sti-with-associations/175627/4 "2009-09-17T22:27:04Z")

</div>

On Sep 17, 11:10 am, Eric [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > > end  
> > > populated with the inheriting class’s name, so that’s fine, but I was  
> > > polymorphic associations are used when you’ve got objects from  
> > > class ThingB \< AR::Base  
> > > class Asset \< ActiveRecord::Base  
> > > class Image \< Asset  
> > > through the association, and even if I manually set user\_id in Asset  
> > > (and user\_type, just for fun), Video.first.user comes up nil. So, STI  
> > > is working as expected, but the association is broken in some way that  
> > > leads me to wonder whether Asset needs some connection with User  
> > > (unlikely, given the docs and commentary I’ve been able to find), or  
> > > whether the STI classes need some more connections to the base class  
> > > in order for User to pass through the STI.
> 
> -eric

OK, so setting user\_type to “User” manually in the base class does  
seem to work. I’m not sure why I couldn’t find the user from (e.g.)  
@sound before, but that’s water under the bridge now. The problem now  
seems to be that even though Sound[,Video,etc.] are polymorphic to  
User, the user\_type attribute in the base class is not getting set  
when saved through an inheriting class. Why could this be? Is there  
some kind of accepts\_nested\_attributes\_for catch that I’m not  
accounting for?

Alternatively, is there a way to see the mechanism by which the type  
field is set? More explicit logging, perhaps?

-eric

---

<div class="post-metadata">

**Author:** ![eric](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/898d66/32.png) [@eric](https://www.ruby-forum.com/u/eric)\
**Post date:** [September 19, 2009, 1:36pm UTC](https://www.ruby-forum.com/t/polymorphic-sti-with-associations/175627/5 "2009-09-19T13:36:06Z")

</div>

As my knowledge, it should be :

class Asset \< ActiveRecord::Base  
belongs\_to :userable, :polymorphic =\> true

def userable\_type=(sType)  
super(sType.to\_s.classify.constantize.base\_class.to\_s)  
end  
end

class Sound \< Asset  
end

class User \< ActiveRecord::Base  
has\_many :assets , :as=\>:userable  
end

and in your assets table you must have 2 columns : userable\_id and  
userable\_type

best regards

---

<div class="post-metadata">

**Author:** ![eric](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/898d66/32.png) [@eric](https://www.ruby-forum.com/u/eric)\
**Post date:** [September 18, 2009, 8:14pm UTC](https://www.ruby-forum.com/t/polymorphic-sti-with-associations/175627/6 "2009-09-18T20:14:50Z")

</div>

On Sep 17, 2:10 pm, Eric [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> end  
> in order for User to pass through the STI.

Not sure what the issue you’re experiencing is - I’ll have to mock  
some things up and try it. But I’ll reiterate that the :polymorphic is  
not needed on those belongs\_to declarations. The record that they  
point to (a User) is always in the same table. You wouldn’t even need  
it going the other way (some kind of User belongs\_to :media, for  
instance).

Oh, and that has\_many isn’t (AFAIK) valid syntax…

–Matt J.

---

<div class="post-metadata">

**Author:** ![eric](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/898d66/32.png) [@eric](https://www.ruby-forum.com/u/eric)\
**Post date:** [September 22, 2009, 10:12am UTC](https://www.ruby-forum.com/t/polymorphic-sti-with-associations/175627/7 "2009-09-22T10:12:14Z")

</div>

no, it still work event your class is inherited more than one level

---

<div class="post-metadata">

**Author:** ![eric](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/898d66/32.png) [@eric](https://www.ruby-forum.com/u/eric)\
**Post date:** [September 20, 2009, 8:09pm UTC](https://www.ruby-forum.com/t/polymorphic-sti-with-associations/175627/8 "2009-09-20T20:09:55Z")

</div>

On Sep 19, 7:33 am, robdoan [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> As my knowledge, it should be :

[snip]

> def userable\_type=(sType)  
> super(sType.to\_s.classify.constantize.base\_class.to\_s)  
> end  
> end

Um, no. If you’re needing to do this, you’ve done something seriously  
wrong. This is already supported by :polymorphic =\> true. Also note  
that your “solution” here will fail if the class associated to the  
table (Asset in this case) is more than one level above the class  
being stored (ie Asset \> Sound \> Mp3 will try to find records in a  
‘sounds’ table =\> FAIL)

–Matt J.
