2009-10-21 57 views
2

我正在使用Single Table Inheritance來管理不同類型的項目。 我決定存儲一些與每個項目類型相關的信息。所以我創建了「model_type」字段作爲主鍵的新表「project_types」。主鍵值是「項目」表的「類型」字段的值。 問題:當我試圖與Project對象ProjectTypes對象關聯時,它總是返回null。STI和has_many與「type」列的關聯作爲鍵

>> p = Project.find(:first) 
=> #<SiteDesign id: 1, type: "SiteDesign", name: "1", description: "dddd", concept: "d", client_id: 40, created_at: "2009-10-15 08:17:45", updated_at: "2009-10-15 08:17:45"> 
>> p.project_type 
=> nil 

獲取與ProjectTypes項目相關聯的項目是可以的。有沒有辦法讓它正常工作?

型號:

class Project < ActiveRecord::Base 
    belongs_to :project_type, :class_name => "ProjectTypes", :foreign_key => "model_name" 
end 

class SiteDesign < Project 
end 

class TechDesign < Project 
end 

class ProjectTypes < ActiveRecord::Base 
    self.primary_key = "model_name" 
    has_many :projects, :class_name => "Project", :foreign_key => "type" 
end 

遷移:

class CreateProjectTypes < ActiveRecord::Migration 
    def self.up 
    create_table :project_types, :id => false do |t| 
     t.string :model_name , :null => false 
     t.string :name, :null => false 
     t.text :description 

     t.timestamps 
    end 

    add_index :project_types, :model_name, :unique => true 


    #all project types that are used. 
    models_names = {"SiteDesign" => "Site design", 
     "TechDesign" => "Tech design"} 

    #key for model_name and value for name 
    models_names.each do |key,value| 
     p = ProjectTypes.new(); 
     p.model_name = key 
     p.name = value 
     p.save 
    end 

    end 

    def self.down 
    drop_table :project_types 
    end 
end 

class CreateProjects < ActiveRecord::Migration 
    def self.up 
    create_table :projects do |t| 
     t.string :type 
     t.string :name 
     t.text :description 
     t.text :concept 
     t.integer :client_id 

     t.timestamps 
    end 
    end 

    def self.down 
    drop_table :projects 
    end 
end 

回答

3

並不奇怪你得到的問題。通過從純粹的STI系統轉移到您當前的系統,您可能會通過將其中一部分與另一部分相混合來打破您正在使用的模式。

我會親自去類似:

class Project < ActiveRecord::Base 
    attr_readonly(:project_type) 
    belongs_to :project_type 
    before_create :set_project_type 

    def set_project_type() 
     project_type = ProjectType.find_by_model_name(this.class) 
    end 
end 

class SiteProject < Project 
end 

class TechProject < Project 
end 

class ProjectType < ActiveRecord::Base 
    has_many :projects 
end 

與遷移:

class CreateProjectTypes < ActiveRecord::Migration 
    def self.up 
    create_table :project_types do |t| 
     t.string :model_name , :null => false 
     t.string :name, :null => false 
     t.text :description 

     t.timestamps 
    end 

    add_index :project_types, :model_name, :unique => true 


    #all project types that are used. 
    models_names = {"SiteDesign" => "Site design", 
     "TechDesign" => "Tech design"} 

    #key for model_name and value for name 
    models_names.each do |key,value| 
     p = ProjectTypes.new(); 
     p.model_name = key 
     p.name = value 
     p.save 
    end 

    end 

    def self.down 
    drop_table :project_types 
    end 
end 

class CreateProjects < ActiveRecord::Migration 
    def self.up 
    create_table :projects do |t| 
     t.string :type 
     t.references :project_type, :null => false 
     t.text :description 
     t.text :concept 
     t.integer :client_id 

     t.timestamps 
    end 
    end 

    def self.down 
    drop_table :projects 
    end 
end 

只是清理東西,它也有助於澄清自己在做什麼。你的'ProjectType'表純粹是爲了額外的數據,你的繼承樹仍然存在。我還引入了一些檢查,以確保始終設置項目類型(並根據模型名稱正確設置),並通過使屬性爲只讀來保存項目類型,從而阻止您更改項目類型。