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 -~----------~----~----~----~------~----~------~--~---