STI и ассоциация has_many со столбцом “type” в качестве ключа

StackOverflow https://stackoverflow.com/questions/1600432

Вопрос

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

Модели:

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
Это было полезно?

Решение

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top