Nish Patel
2007-Nov-02  11:38 UTC
Polymorphic Associations - Customer & Supplier have Phones
INTRO
I am currently working for a company who want a new e-commerce
interface; I have considered using ruby on rails. I am completely stuck
I dont know what has gone wrong I am trying to create customers or
suppliers numbers and it wont do anything, it will actually ignore the
data I input and just show blank without any errors. Hopefully this
example can help others in the future if they want to do something
similar what I have.
SCENARIO
I have four tables, which are
- Addresses
- Customers
- Suppliers
- Phones
I have used polymorphic association because a customer and a supplier
can have more than one or many addresses and phone numbers etc. So I
basically created my tables using Migration, then used ruby Scaffold to
create models, views etc. This is how I have created the relationships
note that I am currently just going to focus on the phones table with
customer or supplier once I have this right I can easily do the
addresses:
Phones Table:
class CreatePhones < ActiveRecord::Migration
  def self.up
    create_table :phones do |t|
      t.column :created_at, :datetime
      t.column :updated_at, :datetime
    t.column :phonable_id, :integer, :null => false
    t.column :phonable_type, :string, :null => false
      t.column :tag_for_phone, :string # could be "work phone",
"home
phone", etc
    t.column :number, :string # redundant but makes searching easier
    t.column :country_code, :string
     t.column :area_code, :string
     t.column :local_number, :string
    end
    add_index :phones, :number # don''t make this unique!
  end
  def self.down
    drop_table :phones
  end
end
Customer Table:
class CreateCustomers < ActiveRecord::Migration
  def self.up
    create_table :customers do |t|
      t.column :first_name, :string
      t.column :surname, :string
    end
  end
  def self.down
    drop_table :customers
  end
end
Supplier Table:
class CreateSuppliers < ActiveRecord::Migration
  def self.up
    create_table :suppliers do |t|
      t.column :name, :string
    end
  end
  def self.down
    drop_table :suppliers
  end
end
Here are the relationships between tables:
Phones Model:
 class Phone < ActiveRecord::Base
  belongs_to :phonable, :polymorphic => true
  has_one :customer, :as => :phonable
  has_one :supplier, :as => :phonable
  end
Customer Model:
class Customer < ActiveRecord::Base
   has_many :phones, :as => :phonable, :dependent => :destroy
   has_many :addresses, :as => :addressable, :dependent => :destroy
def full_name
  "#{first_name} #{surname}"
  end
  end
Supplier Model:
class Supplier < ActiveRecord::Base
   has_many :phones, :as => :phonable, :dependent => :destroy
   has_many :addresses, :as => :addressable, :dependent => :destroy
   def full_name
     name
   end
    end
Now here are the controllers that I have used:
Phones Controller:
class PhonesController < ApplicationController
 def index
        list
    render :action => ''list''
   end
  # GETs should be safe (see
http://www.w3.org/2001/tag/doc/whenToUseGet.html)
  verify :method => :post, :only => [ :destroy, :create, :update ],
         :redirect_to => { :action => :list }
  def list
    @phone_pages, @phones = paginate :phones, :per_page => 10
  end
  def show
    @phone = Phone.find(params[:id])
  end
  def new
    @customer = Customer.find(params[:customer_id]) if
params[:customer_id]
     @supplier = Supplier.find(params[:supplier_id]) if
params[:supplier_id]
      @phone = Phone.new
      end
  def create
              @customer = Customer.find(params[:customer][:id]) if
params[:customer]
          @supplier = Supplier.find(params[:supplier][:id]) if
params[:supplier]
      @phone = Phone.new(params[:phone])
  @phone.number = "+#{@phone.country_code} #{@phone.area_code}
#{@phone.local_number}"
  respond_to do |format|
      if @phone.save
        @customer.phones << @phone if @customer
      @supplier.phones << @phone if @supplier
    @customer.save if @customer
  @supplier.save if @supplier
flash[:notice] = "Successfully added #{@phone.number}."
  format.html { redirect_to phone_url(@phone) }
   format.xml  { head :created, :location => phone_url(@phone) }
    else
  flash[:notice] = "Unable to add #{@phone.number}."
    format.html { render :action => "new" }
        format.xml  { render :xml => @phone.errors.to_xml }
    end
  end
  end
def edit
    @phone = Phone.find(params[:id])
  end
  def update
    @phone = Phone.find(params[:id])
    if @phone.update_attributes(params[:phone])
      flash[:notice] = ''Phone was successfully updated.''
      redirect_to :action => ''show'', :id => @phone
    else
      render :action => ''edit''
    end
  end
  def destroy
    Phone.find(params[:id]).destroy
    redirect_to :action => ''list''
  end
end
Customers Controller:
class CustomersController < ApplicationController
  def index
    list
    render :action => ''list''
  end
  # GETs should be safe (see
http://www.w3.org/2001/tag/doc/whenToUseGet.html)
  verify :method => :post, :only => [ :destroy, :create, :update ],
         :redirect_to => { :action => :list }
  def list
    @customer_pages, @customers = paginate :customers, :per_page => 10
  end
  def show
    @customer = Customer.find(params[:id])
  end
  def new
    @customer = Customer.new
  end
  def create
    @customer = Customer.new(params[:customer])
    if @customer.save
      flash[:notice] = ''Customer was successfully created.''
      redirect_to :action => ''list''
    else
      render :action => ''new''
    end
  end
  def edit
    @customer = Customer.find(params[:id])
  end
  def update
    @customer = Customer.find(params[:id])
    if @customer.update_attributes(params[:customer])
      flash[:notice] = ''Customer was successfully updated.''
      redirect_to :action => ''show'', :id => @customer
    else
      render :action => ''edit''
    end
  end
  def destroy
    Customer.find(params[:id]).destroy
    redirect_to :action => ''list''
  end
end
Suppliers Controller:
class SuppliersController < ApplicationController
  def index
    list
    render :action => ''list''
  end
  # GETs should be safe (see
http://www.w3.org/2001/tag/doc/whenToUseGet.html)
  verify :method => :post, :only => [ :destroy, :create, :update ],
         :redirect_to => { :action => :list }
  def list
    @supplier_pages, @suppliers = paginate :suppliers, :per_page => 10
  end
  def show
    @supplier = Supplier.find(params[:id])
  end
  def new
    @supplier = Supplier.new
  end
  def create
    @supplier = Supplier.new(params[:supplier])
    if @supplier.save
      flash[:notice] = ''Supplier was successfully created.''
      redirect_to :action => ''list''
    else
      render :action => ''new''
    end
  end
  def edit
    @supplier = Supplier.find(params[:id])
  end
  def update
    @supplier = Supplier.find(params[:id])
    if @supplier.update_attributes(params[:supplier])
      flash[:notice] = ''Supplier was successfully updated.''
      redirect_to :action => ''show'', :id => @supplier
    else
      render :action => ''edit''
    end
  end
  def destroy
    Supplier.find(params[:id]).destroy
    redirect_to :action => ''list''
  end
end
This is my phones helper:
module PhonesHelper
   def phonable_path(phonable)
    if phonable.kind_of? Customer
      customer_path(phonable)
      else
        supplier_path(phonable)
      end
    end
end
Now for the pages I have used the following code and what happens is
that I try to add a phone number for the customer and it wont add the
telephone number at all I have tried everything:
Customers View Show:
<% unless @user.phones.empty? %>
<label>Phone Numbers</label>
  <% for phone in @customer.phones %>
    <%= link_to phone.number, phone_path(phone) %><br />
  <% end %>
<% end %>
<br />
<%= link_to ''Add Phone Number'', new_user_phone_path(@user)
%>
<br />
Phones View New:
<h1>New Phone Number</h1>
<label>For</label>
<span>
<%=h @customer.full_name if @customer -%>
<%=h @supplier.full_name if @supplier -%>
</span><br />
<% form_for :phone, :url => phones_path do |form| -%>
<%= (hidden_field :customer, :id, :value => @customer.id) if @customer
-%>
<%= (hidden_field :supplier, :id, :value => @supplier.id) if @supplier
-%>
<%= render :partial => ''form'', :object => form -%>
<p><%= submit_tag ''Create'' -%></p>
<% end -%>
Phones View Show:
<% if @phone.phonable_type == ''Customer'' -%>
 <label>Phone for</label>
 <span>
<%= link_to @phone.phonable.full_name, phonable_path(@phone.phonable)
-%><br />
</span>
<% end -%>
<br /><% if @phone.phonable_type == ''Supplier'' -%>
<label>Phone for</label>
<span>
<%= link_to @phone.phonable.full_name, supplier_path(@phone.phonable)
-%><br />
</span>
<% end -%>
Phones View _form :
<%= error_messages_for ''phone'' %>
<%= form.hidden_field :phonable_type %>
<%= form.hidden_field :phonable_id %>
<!--[form:phone]-->
<p><label for="phone_created_at">Created
at</label><br/>
<%= datetime_select ''phone'', ''created_at''
%></p>
<p><label for="phone_updated_at">Updated
at</label><br/>
<%= datetime_select ''phone'', ''updated_at''
%></p>
<p><label for="phone_tag_for_phone">Tag for
phone</label><br/>
<%= text_field ''phone'', ''tag_for_phone''
%></p>
<p><label
for="phone_number">Number</label><br/>
<%= text_field ''phone'', ''number''
%></p>
<p><label for="phone_country_code">Country
code</label><br/>
<%= text_field ''phone'', ''country_code''
%></p>
<p><label for="phone_area_code">Area
code</label><br/>
<%= text_field ''phone'', ''area_code'' 
%></p>
<p><label for="phone_local_number">Local
number</label><br/>
<%= text_field ''phone'', ''local_number'' 
%></p>
<!--[eoform:phone]-->
Routes:
map.resources :addresses
  map.resources :phones
    map.resources :suppliers do |supplier|
    supplier.resources :supplier_phones,
    :opaque_name => :phones,
    :controller => :phones
    supplier.resources :supplier_addresses,
    :opaque_name => :addresses,
    :controller => :addresses
  end
  map.resources :customers do |customer|
    customer.resources :customer_phones,
    :opaque_name => :phones,
    :controller => :phones
    customer.resources :customer_addresses,
    :opaque_name => :addresses,
    :controller => :addresses
    end
end
Ok so thats it then, I have attached a word document if you want things
to be clearly labelled, please can someone help me to complete this
tricky situation thank you!!!
Attachments:
http://www.ruby-forum.com/attachment/851/code.doc
-- 
Posted via http://www.ruby-forum.com/.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Talk" group.
To post to this group, send email to
rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-talk-unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/rubyonrails-talk?hl=en
-~----------~----~----~----~------~----~------~--~---