# Polymorphic relation question

**URL:** <https://www.ruby-forum.com/t/polymorphic-relation-question/60078>\
**Category:** Rails\
**Created:** [May 10, 2006, 12:50am UTC](https://www.ruby-forum.com/t/polymorphic-relation-question/60078 "2006-05-10T00:50:14Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![scott](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3e96dc/32.png) [@scott](https://www.ruby-forum.com/u/scott)\
**Post date:** [May 10, 2006, 12:50am UTC](https://www.ruby-forum.com/t/polymorphic-relation-question/60078/1 "2006-05-10T00:50:14Z")

</div>

I am trying to get polymorphic relations to work for my app. What I am  
trying to do is explained by this picture  
[http://iroll.org/code/](http://iroll.org/code/)  
I can’t figure out the code for in the controller to create a new  
phone\_number and assign it to a person. I have tried everything I can  
think of.

A) do my models look correct?  
B) what would the commands look like in the console or a controller  
action look like to save something to a person?

I have been messing with this all afternoon, I got the example in the  
recipe book working, I just can’t get this working.

---

<div class="post-metadata">

**Author:** ![scott](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3e96dc/32.png) [@scott](https://www.ruby-forum.com/u/scott)\
**Post date:** [May 10, 2006, 1:27am UTC](https://www.ruby-forum.com/t/polymorphic-relation-question/60078/2 "2006-05-10T01:27:38Z")

</div>

scott \<scottnj@…\> writes:

> action look like to save something to a person?
> 
> I have been messing with this all afternoon, I got the example in the  
> recipe book working, I just can’t get this working.

These models will definitely work. I have a _very_ similar structure in  
my app,  
except that I reuse the same contact-item PK ID in the  
address/phone/email  
tables (which was probably more hassle than it was worth).

The creation code in controller goes something like this:

@person = Person.find(params[:id])  
@person.create\_phone(params[:phone])

Tough, huh? It all happens in the model:

class Person

end

---

<div class="post-metadata">

**Author:** ![scott](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3e96dc/32.png) [@scott](https://www.ruby-forum.com/u/scott)\
**Post date:** [May 10, 2006, 1:42am UTC](https://www.ruby-forum.com/t/polymorphic-relation-question/60078/3 "2006-05-10T01:42:51Z")

</div>

Kian \<kianwright@…\> writes:

> > 
> 
> tables (which was probably more hassle than it was worth).  
> end

Well that was weird. Guess I accidentally posted the response. Anyway,  
something  
like this:  
class Person  
def create\_contact\_item(type)  
contact\_item = ContactItem.new({:person\_id =\> self.id,  
:addressable\_type =\>  
type})  
contact\_item.save && contact\_item  
end

def create\_phone(params)  
contact\_item = create\_contact\_item(AddressableType::PHONE)  
phone = Phone.new(params)  
phone.id = contact\_item.id  
phone.save && phone  
end  
end

The trouble with your model is going to be that you need to get a unique  
ID for  
the phone/address/email to be the PK, but you also need it to be already  
present  
in the contact-item table to satisfy the foreign key. Unless you  
generate it  
external to the database (not recommended), I don’t see how you will be  
able to  
easily do it. I’d recommend trying to use the same ID for the  
contact-item and  
the child tables too.

If you’re really ambitious, you can set up a person has many phones and  
probably  
override the \<\< method on the person.phones to accept your request  
parameters  
and create a new phone and contact item. That’d be cool.

---

<div class="post-metadata">

**Author:** ![scott](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3e96dc/32.png) [@scott](https://www.ruby-forum.com/u/scott)\
**Post date:** [May 10, 2006, 1:46am UTC](https://www.ruby-forum.com/t/polymorphic-relation-question/60078/4 "2006-05-10T01:46:57Z")

</div>

> These models will definitely work. I have a _very_ similar structure in  
> my app,  
> except that I reuse the same contact-item PK ID in the  
> address/phone/email  
> tables (which was probably more hassle than it was worth).
> 
> The creation code in controller goes something like this:
> 
> @person = Person.find(params[:id])  
> @person.create\_phone(params[:phone])
> 
> Tough, huh? It all happens in the model:
> 
> class Person
> 
> end

That does not seem to work for me.  
In the console I type:  
p = Person.find(:first)  
p.create\_email(:label =\> “work”, :address =\> "removed\_email\_address@domain.invalid)

The second line returns:  
NoMethodError: undefined method ‘create\_email’ for #Person:0x37a66e8

What’s different?

---

<div class="post-metadata">

**Author:** ![scott](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3e96dc/32.png) [@scott](https://www.ruby-forum.com/u/scott)\
**Post date:** [May 10, 2006, 2:25am UTC](https://www.ruby-forum.com/t/polymorphic-relation-question/60078/5 "2006-05-10T02:25:49Z")

</div>

On 9-May-06, at 7:46 PM, scott wrote:

> > @person.create\_phone(params[:phone])  
> > p.create\_email(:label =\> “work”, :address =\> "removed\_email\_address@domain.invalid)
> 
> The second line returns:  
> NoMethodError: undefined method ‘create\_email’ for #Person:0x37a66e8
> 
> What’s different?

I too have virtually the same data model, and have the same problem  
as you Scott.

…which leads me to ask if there’s a way to query all methods for an  
object, which may help debug such a symptom.

Jodi

---

<div class="post-metadata">

**Author:** ![scott](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3e96dc/32.png) [@scott](https://www.ruby-forum.com/u/scott)\
**Post date:** [May 10, 2006, 8:40am UTC](https://www.ruby-forum.com/t/polymorphic-relation-question/60078/6 "2006-05-10T08:40:55Z")

</div>

scott \<scottnj@…\> writes:

> 

Sorry, I didn’t expand on it in more detail. I assumed that you had a  
model or  
class or module that enumerates the addressable-type values. Instead of  
AddressableType::Phone, put whatever value you use to for your  
addressable-type  
field in the database to indicate that the contact-item is a phone. At  
least  
that’s what I think that field means. Ignore this comment if that’s not  
what the  
field is in your model. Maybe I misunderstand…

---

<div class="post-metadata">

**Author:** ![scott](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3e96dc/32.png) [@scott](https://www.ruby-forum.com/u/scott)\
**Post date:** [May 10, 2006, 3:42am UTC](https://www.ruby-forum.com/t/polymorphic-relation-question/60078/7 "2006-05-10T03:42:29Z")

</div>

Kian wrote:

> Well that was weird. Guess I accidentally posted the response. Anyway,  
> something  
> like this:  
> class Person  
> def create\_contact\_item(type)  
> contact\_item = ContactItem.new({:person\_id =\> self.id,  
> :addressable\_type =\>  
> type})  
> contact\_item.save && contact\_item  
> end
> 
> def create\_phone(params)  
> contact\_item = create\_contact\_item(AddressableType::PHONE)  
> phone = Phone.new(params)  
> phone.id = contact\_item.id  
> phone.save && phone  
> end  
> end
> 
> The trouble with your model is going to be that you need to get a unique  
> ID for  
> the phone/address/email to be the PK, but you also need it to be already  
> present  
> in the contact-item table to satisfy the foreign key. Unless you  
> generate it  
> external to the database (not recommended), I don’t see how you will be  
> able to  
> easily do it. I’d recommend trying to use the same ID for the  
> contact-item and  
> the child tables too.
> 
> If you’re really ambitious, you can set up a person has many phones and  
> probably  
> override the \<\< method on the person.phones to accept your request  
> parameters  
> and create a new phone and contact item. That’d be cool.

I think I see what you are doing here, but when I try  
p = Person.find(:first)  
p.create\_phone(:label =\> “work”)

I get  
NameError: unitialized constant AddressableType

How do you get type passed for the polymorphic relations? I also tried  
putting it in quotes,that stores “AddressableType::PHONE” in the table  
but addressable\_id is still null.

---

<div class="post-metadata">

**Author:** ![scott](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/3e96dc/32.png) [@scott](https://www.ruby-forum.com/u/scott)\
**Post date:** [May 20, 2006, 12:29pm UTC](https://www.ruby-forum.com/t/polymorphic-relation-question/60078/8 "2006-05-20T12:29:28Z")

</div>

scott, you wrote,

> I am trying to get polymorphic relations to work for my app. What I am  
> trying to do is explained by this picture  
> [http://iroll.org/code/](http://iroll.org/code/)  
> I can’t figure out the code for in the controller to create a new  
> phone\_number and assign it to a person. I have tried everything I can  
> think of.

You’ve got your polymorph relationships around the wrong way. The  
people  
have many contact\_items as addressable, ie.:

class Person \< ActiveRecord::Base  
has\_many :contact\_items, :as =\> :addressable

```
# then your create_phone_number method would look something like 

```

this  
def create\_phone\_number(params)  
ci = ContactItem.new(:person\_id =\> id)

```
  # this next line *is* the polymorphism
  ci.addressable = PhoneNumber.create(params)
  ci.save
  contact_items << ci
end

```

end

Note that one of the benefits of polymorphism is that you DON’T need to  
worry  
about overlapping PKs in the various address tables, and you DON’T need  
to  
worry about doing the addressable\_type yourself. Rails handles the type  
for  
you, and the fact that there’s a type means that the PKs can (and  
should)  
overlap, that’s not a problem because the foreign key is really a  
multi-column foreign key including the addressable\_type.

So, just to complete the picture, contact\_item.rb was correct, but all  
your  
individual address tables need to drop the :as =\> :addressable, here’s  
the  
PhoneNumber one, the rest are the same idea:

class PhoneNumber \< ActiveRecord::Base  
has\_one :contact\_item  
end

To see this in the console:

> > p = Person.create( :first\_name =\> “Foo” )  
> > p.create\_phone\_number(:first\_numbers =\> “123”, :second\_numbers =\>  
> > “456”)  
> > p.contact\_items[0].addressable\_type  
> > p.contact\_items[0].addressable.first\_numbers
