Создание записей наследования одной таблицы в Rails - PullRequest
2 голосов
/ 21 октября 2009

Я использую наследование одной таблицы для своего приложения. Мой полиморфный тип - это обслуживание только с одним подтипом, прямо сейчас, с именем OilChange. У меня проблемы с созданием записей в моем методе создания в контроллере. Вот код.

@log = Log.new(params[:log])
@log.maintenance = Maintenance.new(params[:maintenance])

Хэш params [: maintenance] имеет ключи {: name,: type}. Я могу проверить их существование и значения, распечатав их следующим образом

print params[:maintenance][:name]
print params[:maintenance][:type]

Если я передам "OilChange" для значения клавиши типа: запись техобслуживания будет иметь тип Maintenance, а не OilChange. Я могу убедиться в этом, найдя запись в консоли REPL. Поле типа равно нулю. Я могу заставить его работать так, как я хочу, добавив следующую строку.

@log.maintenance.type = params[:maintenance][:type]

Но это ужасно. Что мне интересно, так это то, почему метод create не устанавливает поле типа, так как поле имени просто находит?

Два типа, которые вы видите, выглядят так в моей схеме.rb

create_table "logs", :force => true do |t|
  t.date     "date"
  t.text     "description"
  t.string   "title"
  t.string   "summary"
  t.integer  "car_id"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.integer  "maintenance_id"
  t.integer  "mileage"
end

create_table "maintenances", :force => true do |t|
  t.string   "name"
  t.string   "type"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.string   "oil_brand"
  t.string   "oil_type"
  t.string   "oil_filter_type"

Мои модели выглядят так.

class Log < ActiveRecord::Base
belongs_to :car
has_and_belongs_to_many :tags
  belongs_to :maintenance
end

class Maintenance < ActiveRecord::Base
  has_one :log
end

class OilChange < Maintenance
end

ТИА!

Ответы [ 2 ]

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

Конкретный ответ заключается в том, что атрибут type, как и многие специальные атрибуты Rails, защищен от массового присвоения. (Посмотрите :attr_protected в документации.)

Ответ на более общую проблему заключается в том, что вы недостаточно доверяете своим моделям. Если вы хотите создать запись типа OilChange, вы не должны вызывать Maintenance.new или Maintenance.create. Вместо этого позвоните OilChange.new или OilChange.create, и Rails автоматически позаботится о настройке типа и выполнении всей фоновой работы за вас.

0 голосов
/ 10 апреля 2011

Попробуйте следующий код:

begin
  klass = Module.const_get(params[:maintenance][:type])
  @log.maintenance = klass.new(params[:maintenance])
  if ! @log.maintenance.is_a?(Maintenance)
    @log.maintenance = Maintenance.new(params[:maintenance])
  end
rescue NameError
  @log.maintenance = Maintenance.new(params[:maintenance])
end

Если вы хотите, чтобы в вашей базе данных были только подклассы обслуживания, выполните следующие действия в своем классе обслуживания:

class Maintenance < ActiveRecord::Base
  validates_presence_of :type
  # other stuff goes here
end

Этот код создаст недопустимый класс обслуживания, если параметры содержат неправильный тип. Если они содержат правильный тип, будет создан экземпляр указанного класса.

Если ваши модели используют пространства имен, вы можете изучить эту статью вместо использования Module.const_get:

...