2

さまざまなタイプのプロジェクトを管理するために単一テーブル継承を使用しています。各プロジェクトタイプに関連するいくつかの情報を保存することにしました。そこで、「model_type」フィールドを主キーとして新しいテーブル「project_types」を作成しました。主キーの値は、「プロジェクト」テーブルの「タイプ」フィールドの値です。問題:ProjectオブジェクトProjectTypesオブジェクトに関連付けようとすると、常に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

ProjectTypesプロジェクトに関連付けられたプロジェクトを取得することはOKです。正しく動作させる方法はありますか?

モデル:

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
4

1 に答える 1

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'テーブルは純粋に追加データ用であり、継承ツリーは引き続き存在します。また、プロジェクトタイプが常に設定されていること(モデル名に基づいて正しく設定されていること)を確認するためにいくつかのチェックを行い、属性を読み取り専用にすることで、保存後にプロジェクトタイプを変更できないようにしました。

于 2009-10-21T12:38:04.187 に答える