這是一個在rails中的多態關聯的一個簡明教程。web
最近的一個ruby on rails項目,用戶和公司的模型都有地址。數據庫
我要建立一個地址表,包含用戶和公司表的引用,比直接作下去要好一點,這回讓個人數據庫設計保持乾淨。ruby
個人第一印象是,這彷佛很難實現,外面全部的討論及教程都只說明瞭在model如何設置,可是並無說明在controller和view如何使用它。我好一頓放狗,也沒有獲得太多的幫助。less
令我感到驚喜是其實在rails設置並使用多態表單是很簡單的。數據庫設計
首先依然是先設置model結構:post
class Company< ActiveRecord::Base has_one :address, :as =>; :addressable, :dependent => :destroy end class User < ActiveRecord::Base has_one :address, :as => :addressable, :dependent => :destroy end class Address < ActiveRecord::Base belongs_to :addressable, :polymorphic => true end
接下來是建立一個Address表來保存地址:url
class CreateAddresses < ActiveRecord::Migration def self.up create_table :addresses do |t| t.string :street_address1, :null => false t.string :street_address2 t.string :city, :null => false t.string :region, :null => false t.string :postcode, :null => false, :limit => 55 t.integer :addressable_id, :null => false t.string :addressable_type, :null => false t.timestamps end end def self.down drop_table :addresses end end
接下來是controller,你只須要修改controller中的"new","create","edit","update"四個action,好讓須要的時候能夠訪問和修改address。spa
class CompaniesController < ApplicationController def new @company = Company.new @company.address = Address.new end def edit @company = Company.find(params[:id]) @company.address = Address.new unless @company.address != nil end def create @company = Company.new(params[:company]) @company.address = Address.new(params[:address]) if @company.save @company.address.save flash[:notice] = 'Company was successfully created.' redirect_to(@company) else render :action => 'new' end end def update @company = Company.find(params[:id]) if @company.update_attributes(params[:company]) @company.address.update_attributes(params[:address]) flash[:notice] = 'Company was successfully updated.' redirect_to(@company) else render :action => 'edit' end end end
最後一件事是讓address在表單中能夠正常工做,咱們這裏使用field_for方法:設計
<% form_for(@company) do |f| %> <%= f.error_messages %> <dl> <%= f.text_field :name %> <%= f.text_field :telephone %> <%= f.text_field :fax %> <%= f.text_field :website_url %> </dl> <% fields_for(@company.address) do |address_fields| %> <%= address_fields.hidden_field :addressable_id %> <%= address_fields.hidden_field :addressable_type %> <dl> <%= address_fields.text_field :street_address1 %> <%= address_fields.text_field :street_address2 %> <%= address_fields.text_field :city %> <%= address_fields.text_field :region %> <%= address_fields.text_field :postcode %> </dl> <% end %> <% end %>
到這就應該能夠正常工做了。 code
有人要問了,若是我去的了address對象,可否反向取得Company或者User對象呢?答案固然是確定的。
@address = Address.find(params[:id]) @address.addressable 這樣就能夠訪問了。