我过去使用 STI 没有问题,但在尝试使用自定义继承列时在 Rails 4(4.0.5 和 4.1.4)上遇到过这个问题。问题是该列不会自动设置。
给定:
class Place < ActiveRecord::Base
self.abstract_class = true
self.inheritance_column = :category
end
class City < Place
self.table_name = 'places'
end
City.create location: 'Baltimore'
类别未设置,但我可以手动设置它
City.create location: 'Baltimore', category: 'City'
我不确定是什么问题。 Places 模型只有位置(字符串)和类别(字符串)列。
感谢您的帮助
我也为此苦苦挣扎了几分钟。问题是
self.abstract_class = true
.
当您将其设置为 true 时,该类将从 STI 的继承链中消失,并且 Rails 无法正确发现表名。
但是如果你的基类——像我的——是一个抽象类,一个你不想持久化到你的数据库中的类,该怎么办?
简单:在您的基类中添加一个
validates :type, presence: true
,并在您的迁移中创建您的type
列null: false
。
这个答案来自官方 Rails 文档,这里:
# Consider the following default behaviour:
Shape = Class.new(ActiveRecord::Base)
Polygon = Class.new(Shape)
Square = Class.new(Polygon)
Shape.table_name # => "shapes"
Polygon.table_name # => "shapes"
Square.table_name # => "shapes"
Shape.create! # => #<Shape id: 1, type: nil>
Polygon.create! # => #<Polygon id: 2, type: "Polygon">
Square.create! # => #<Square id: 3, type: "Square">
# However, when using abstract_class, Shape is omitted from the hierarchy:
class Shape < ActiveRecord::Base
self.abstract_class = true
end
Polygon = Class.new(Shape)
Square = Class.new(Polygon)
Shape.table_name # => nil
Polygon.table_name # => "polygons"
Square.table_name # => "polygons"
Shape.create! # => NotImplementedError: Shape is an abstract class and cannot be instantiated.
Polygon.create! # => #<Polygon id: 1, type: nil>
Square.create! # => #<Square id: 2, type: "Square">
最后说:
请注意,在上面的示例中,要禁止创建普通多边形,您应该使用
,而不是将其设置为抽象类。这样,Polygon 将留在层次结构中,Active Record 将继续正确派生表名。validates :type, presence: true
就像我说的,我还在我的迁移中将
null: false
添加到 type
列。这样我就可以确定我的基类永远不会被持久化到数据库中。