I have been having trouble setting up some relations.
I want to be able to do this:
user.contact_items # an array of addresses, websites, phone
numbers, etc.
user.addresses # an array of addresses
user.websites # an array of websites
user.phone_numbers # an array of phone numbers
etc.
and the same for businesses, charities, etc.
Since users, businesses, and charities all can have multiple contact
items I assume a polymorphic relation makes sense.
I also want to be able to do
address.owner # a user, business, or charity
website.owner # a user, business, or charity
phone_number.owner # a user, business, or charity
etc.
After much searching, reading and experimenting, my head is beginning
to hurt. Can someone get me pointed in the right direction? How do I
setup my models? Will it be possible to add fields to my join table so
I can flag contact items with things like verified, public, labels,
etc?
Maybe the below will help. I also know that railsenvy has a good video
on this.
First of all, it is the tables and associations that are plural, not
the classes.
I suggest that you would use single table inheritance for the users
business etc.
You need to have a type column defined in the owners table to signify
class for the record
Here's my suggestion:
class Owner < ActiveRecord::Base
has_many :addresses, :through => :contact_items
has_many :websites, :through => :contact_items
has_many :phone_numbers, :through => :contact_items
end
class User < Owner
end
class Business < Owner
end
class Charities < Owner
end
# migration
create_table :owners do |t|
...
t.string :type
end
Polymorphic Association could be is solved like this
class ContactItem < ActiveRecord::Base
belongs_to :owners
belongs_to :contacts, :polymorphic => true
end
# migration
create_table :contact_item do |t|
...
t.string :contact_type
t.integer :contact_id
end
class Address < ActiveRecord::Base
has_one :owner, :thorugh => :contact_items
end
class EmailAddress < ActiveRecord::Base
has_one :owner, :thorugh => :contact_items
end
class PhoneNumber < ActiveRecord::Base
has_one :owner, :thorugh => :contact_items
end
class Website < ActiveRecord::Base
has_one :owner, :thorugh => :contact_items
end
You can use either belongs_to or has_one on the above classes
I couldn't find a complete example of a double polymorphic
relationship so I will post what I have in case someone comes across
this using Google. It seems to be working so far, but I don't know if
I have everything setup correctly yet.
# install as a plugin or as a gem
git submodule add git://github.com/fauna/has_many_polymorphs.git
vendor/plugins/has_many_polymorphs
git submodule init
git submodule update
# setup the models
ruby script/generate model User name:string
ruby script/generate model Business name:string
ruby script/generate model Charity name:string
ruby script/generate model Address street:string street2:string
city:string state:string zip:string
ruby script/generate model EmailAddress address:string
ruby script/generate model Website address:string
ruby script/generate model PhoneNumber number:string
ruby script/generate model Linkage
# edit the linkage migration
class CreateLinkages < ActiveRecord::Migration
def self.up
create_table :linkages do |t|
t.references :origin, :polymorphic => true
t.references :destin, :polymorphic => true
t.timestamps
end
end
def self.down
drop_table :linkages
end
end
My last post was wrong. The only place we need to define the
relationships is in the join model, the other models can be blank. It
is even cleaner now!!!
One problem I still have is the "destins" (addresses ,phones ,emails,
etc.) can belong to many "origins". I need to make this work as a
has_one instead of a has_many.
ruby script/generate model User name:string
ruby script/generate model Business name:string
ruby script/generate model Charity name:string
ruby script/generate model Address street:string street2:string
city:string state:string zip:string
ruby script/generate model EmailAddress address:string
ruby script/generate model Website address:string
ruby script/generate model PhoneNumber number:string
ruby script/generate model Linkage
class CreateLinkages < ActiveRecord::Migration
def self.up
create_table :linkages do |t|
t.references :origin, :polymorphic => true
t.references :destin, :polymorphic => true
t.timestamps
end
end
def self.down
drop_table :linkages
end
end