STI and has_many relationship with type column as key

I am using Single Table Inheritance to manage various types of projects. I decided to keep some information related to each type of project. So I created a new table "project_types" with the "model_type" field as the primary key. The primary key values ​​are the values ​​of the "table" field of the projects. Problem . When I try to bind the ObjectTypes object object, it always returns null.

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

      

Getting the projects associated with the ProjectTypes is fine. Is there a way to do this right?

Models:

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

      

+2


source to share


1 answer


No wonder you're in trouble. Going from a pure STI system to your current system, you are horribly breaking the patterns you use by mixing parts of one with parts of the other.

I would personally go for something like:

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

      



with 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

      

It just clears things up and also helps clarify what you are doing. Your "ProjectType" table is purely for additional data, your inheritance tree still exists. I also threw some checks to make sure your project type is always set (and correct, based on the model name), and only stops you from changing the project type after you save it if the attribute is read-only.

+3


source







All Articles