2009-10-21 5 views
2

J'utilise Single Table Héritage pour gérer différents types de projets. J'ai décidé de stocker des informations associées à chaque type de projet. J'ai donc créé une nouvelle table "project_types" avec le champ "model_type" comme clé primaire. Les valeurs de clé primaire sont des valeurs du champ "type" de la table "projects". Problème: Lorsque j'essaie d'être associé à l'objet Project ProjectTypes de l'objet, il renvoie toujours null.STI et has_many association avec la colonne "type" en tant que clé

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

L'obtention de projets associés au projet ProjectTypes est OK. Y at-il moyen de le faire fonctionner correctement?

Modèles:

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 

:

Migrations
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 

Répondre

3

Pas étonnant que vous obtenez des problèmes. En passant d'un système STI pur à votre système actuel, vous êtes en train de casser les schémas que vous utilisez en mélangeant des parties de l'un avec des parties d'un autre système.

je personnellement aller pour quelque chose comme:

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 

des migrations:

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 

Il nettoie simplement les choses et il aide aussi à clarifier ce que vous faites. Votre table 'ProjectType' est purement pour des données supplémentaires, votre arbre d'héritage existe toujours. J'ai également jeté quelques vérifications pour m'assurer que votre type de projet est toujours défini (et correctement, basé sur le nom du modèle) et vous empêche de changer le type de projet une fois qu'il a été sauvegardé en rendant l'attribut en lecture seule.

Questions connexes