Создание записей наследования одной таблицы в Rails

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

Вопрос

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

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

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

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

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

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

Но это некрасиво.Что мне интересно, так это почему метод create не устанавливает поле type так, как это делает поле name just find?

Два типа, которые вы видите, выглядят следующим образом в моей схеме.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

ТИА!

Это было полезно?

Решение

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

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

Другие советы

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

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:

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