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'表纯粹是为了额外的数据,你的继承树仍然存在。我还引入了一些检查,以确保始终设置项目类型(并根据模型名称正确设置),并通过使属性为只读来保存项目类型,从而阻止您更改项目类型。