I know there is alot of documentation out there on this stuff, but I can't seem to transform the associations in my head into rails even though the setup seems pretty simple.
We start with the user model. Each user potentially has_many addresses, phone numbers and (real estate)开发者_如何学编程 seller_listings while each seller_listing has one user, address and phone number.
Right now, this is what i have:
class User < ActiveRecord::Base
has_many :seller_listings
has_many :phone_numbers
has_many :addresses
class SellerListing < ActiveRecord::Base
belongs_to :user
belongs_to :address
belongs_to :phone_number
class Address < ActiveRecord::Base
belongs_to :user
class PhoneNumber < ActiveRecord::Base
belongs_to :user
mysql> desc seller_listings;
+--------------------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | | NULL | |
| address_id | int(11) | NO | | NULL | |
| phone_number_id | int(11) | NO | | NULL | |
|...snip...
mysql> desc addresses;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | | NULL | |
| address1 | varchar(255) | NO | | NULL | |
|...snip...
mysql> desc phone_numbers;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | | NULL | |
|...snip...
This all kind of works but I feel like it is wrong. When creating a seller_listing for a new user, I have to create then build the address and phone number kinda like so:
# User
if user = User.find_by_email(args['user']['email'])
user.update_attributes(:first_name => args['user']['first_name'],
:last_name => args['user']['last_name'])
else
new_password = User.generate_new_password
user = User.create(:password => new_password, :confirmation_password => new_password,
:email => args['user']['email'],
:first_name => args['user']['first_name'],
:last_name => args['user']['last_name'])
end
# Address
addr = user.addresses.find_or_create_by_address1_and_zip(args['address']['address1'], args['address']['zip'])
# Phone Number
phone = user.phone_numbers.find_or_create_by_number(args['phone_number']['number'])
user.save!
Then once I get the user, I can create the seller listing:
SellerListing.create!(:user_id => user.id, :address_id => addr.id, :phone_number_id => phone.id)
Like I said, this all kinda works but I am trying to clean up the code by using accepts_nested_attributes_for :user, :address, :phone_number in seller_listing but this doesn't work I assume because seller_listing currently has belongs_to :user, :address and :phone_number.
So, I have obviously botched the model association and could use some help if anybody out there has some suggestions.
[edited with after-thought] Is the solution to add has_one :user, :address and :phone_number to seller listing and then when creating do something like:
ruby-1.8.7-p302 > sl=SellerListing.new
ruby-1.8.7-p302 > sl.user.build("last_name"=>"Bar", "first_name"=>"Foo", "email"=>"foobar@example.com")
<repeat for address and phone number>
The answer for me was polymorphic association. Here are my notes regarding the fix I employed:
Polymorphic Associations
User has many seller listings, addresses and phone numbers Seller Listing has one address and one phone number
Database Changes:
Addresses Table
add_column :address_context_id, :integer, :null => false add_column :address_context_type, :string, :null => false
Phone Numbers Table
add_column :phone_number_context_id, :integer, :null => false add_column :phone_number_context_type, :string, :null => false
populate new cols/backfil
Model Associations
Address
belongs_to :address_context, :polymorphic => true
Phone Number
belongs_to :phone_number_context, :polymorphic => true
User
has_many :addresses, :as => :address_context has_many :phone_numbers, :as => :phone_number_context
Seller Listing
has_one :address, :as => :address_context has_one :phone_number, :as => :phone_number_context
Helpful sites
http://media.railscasts.com/videos/154_polymorphic_association.mov
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
http://blog.opensteam.net/past/2008/11/26/polymorphic_controller_nested_routes_polymorphic
精彩评论