在Rails中创建单表继承记录

时间:2009-10-21 13:21:02

标签: ruby-on-rails single-table-inheritance

我正在为我的应用程序使用单表继承。我的多态类型是维护,只有一个子类型,现在名为OilChange。我在控制器中的create方法中创建记录时遇到了问题。这是代码。

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

params [:maintenance]哈希有密钥{:name,:type}。我可以通过如下打印来验证它们的存在和值

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

如果我输入“OilChange”作为:type键的值,则维护记录的类型为Maintenance,而不是OilChange。我可以通过在REPL控制台中查找记录来验证。类型字段为零。我可以通过添加以下行来使其工作。

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

但那很难看。我想知道为什么create方法不设置类型字段,因为它只是找到名称字段?

您在我的schema.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

TIA!

2 个答案:

答案 0 :(得分:3)

具体答案是,type属性与许多Rails的特殊属性一样,受到质量分配的保护。 (在文档中查找:attr_protected。)

更普遍的问题的答案是你不够信任你的模特。如果要创建OilChange类型的记录,则不应致电Maintenance.newMaintenance.create。请改为调用OilChange.newOilChange.create,Rails会自动负责设置类型并为您完成所有后台工作。

答案 1 :(得分:0)

请尝试以下代码:

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

当params包含错误的类型时,此代码将创建无效的Maintenance类。如果它们包含正确的类型,则将创建指定类的实例。

如果您的模型使用名称空间,您可以查看this article而不是使用Module.const_get