2009-10-21 2 views
2

Я использую Single Table Inheritance для управления различными типами проектов. Я решил сохранить некоторую информацию, связанную с каждым типом проекта. Поэтому я создал новую таблицу «project_types» с полем «model_type» в качестве первичного ключа. Значения основного ключа являются значениями поля типа «таблица» проектов. Проблема: Когда я пытаюсь получить связанный с объектом 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» предназначена исключительно для дополнительных данных, ваше дерево наследования все еще существует. Я также бросил некоторые проверки, чтобы убедиться, что ваш тип проекта всегда задан (и правильно, на основе имени модели), и останавливает вас от изменения типа проекта после его сохранения, заставляя атрибут читать только.

Смежные вопросы