Связь STI и has_many со столбцом типа в качестве ключа - PullRequest
2 голосов
/ 21 октября 2009

Я использую Single Table Inheritance для управления различными типами проектов. Я решил сохранить некоторую информацию, связанную с каждым типом проекта. Поэтому я создал новую таблицу "project_types" с полем "model_type" в качестве первичного ключа. Значения первичного ключа - это значения поля «тип» таблицы «проекты». Проблема : Когда я пытаюсь связать объект Project с объектом ProjectTypes, он всегда возвращает ноль.

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

1 Ответ

3 голосов
/ 21 октября 2009

Не удивительно, что у тебя проблемы. Переходя от чистой системы ИППП к вашей нынешней системе, вы ужасно нарушаете используемые шаблоны, смешивая части одного с частями другого.

Лично я бы пошел на что-то вроде:

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' предназначена исключительно для дополнительных данных, ваше дерево наследования все еще существует. Я также добавил несколько проверок, чтобы убедиться, что тип вашего проекта всегда установлен (и правильно, на основе имени модели) и мешает вам изменить тип проекта после его сохранения, сделав атрибут доступным только для чтения.

...