【问题标题】:Creating Single Table Inheritance Records in Rails在 Rails 中创建单表继承记录
【发布时间】:2011-04-10 19:38:45
【问题描述】:

我正在为我的应用程序使用单表继承。我的多态类型是维护,现在只有一个子类型,名为 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]

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

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

但这很丑。我想知道的是为什么 create 方法没有像 name 字段那样设置 type 字段?

你在我的 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!

【问题讨论】:

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


    【解决方案1】:

    具体的答案是type 属性,就像Rails 的许多特殊属性一样,受到保护,不会被批量赋值。 (在文档中查找:attr_protected。)

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

    【讨论】:

    • 我很乐意这样做,但维护类型取决于用户输入。我只是不知道编译时会是什么
    • 没关系。 Ruby 的动态。 >8-> 假设您有一个“维护类型”下拉菜单。只需从“OilChange”之类的下拉菜单中传回值,您就可以调用params[:maintenance_type].constantize.new 来获取您的对象。 (constantize 是 ActiveSupport 提供的方法。)
    • 或者您可以明确设置“类型”:maintenance.type = "OilChange"
    【解决方案2】:

    试试下面的代码:

    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
    

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

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

    【讨论】:

      猜你喜欢
      • 2011-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多