我有一个共享许多属性的图书和下载模型,因此我的目标是从可下载资源模型继承公共属性。
看了STI,但我转而采用了abstract base model class方式:
模型:
class DownloadableResource < ActiveRecord::Base
self.abstract_class = true
attr_accessible :title, :url, :description, :active, :position
validates :title, :url, :description, presence: true
scope :active, where(active: true).order(:position)
end
class Book < DownloadableResource
attr_accessible :cover_url, :authors
validates :cover_url, :authors, presence: true
end
class Download < DownloadableResource
attr_accessible :icon_url
validates :icon_url, presence: true
end
迁移:
class CreateDownloadableResources < ActiveRecord::Migration
def change
create_table :downloadable_resources do |t|
t.string :title
t.string :url
t.text :description
t.boolean :active, default: false
t.integer :position
t.timestamps
end
end
end
class CreateBooks < ActiveRecord::Migration
def change
create_table :books do |t|
t.string :cover_url
t.string :authors
t.timestamps
end
end
end
class CreateDownloads < ActiveRecord::Migration
def change
create_table :downloads do |t|
t.string :icon_url
t.timestamps
end
end
end
迁移后,当我创建新书时,结果远非预期:
> Book.new
=> #<Book id: nil, cover_url: nil, authors: nil, created_at: nil, updated_at: nil>
有人可以了解如何实现抽象基础模型类技术,以便ActiveRecord模型可以通过inheritance共享公共代码,但是可以持久化到不同的数据库表吗?
答案 0 :(得分:10)
通过将模型声明为抽象,您实际上是说没有基础表,并且您希望允许子类化。这意味着:
downloadable_resources
表books
而不是downloadable_resources
正如@Finbarr已经提到的,这也意味着Book
和Download
模型都需要在其表中包含所有属性。
这实际上有用的是什么呢?在我看来并不是很多。您可以共享验证,范围等,但您可以通过包含自定义模块来更轻松地实现所有这些。
为了解决你的问题,我可能采用不同的方法。我会创建另一个名为DownloadableContent
的模型,它将是自包含的。它将包括验证,表将具有所有属性。最后,模型Book
和Download
将与has_one
模型具有多态DownloadableContent
关系。
您可以采用STI方法,但我通常不喜欢将所有自定义属性混合在一起。
答案 1 :(得分:5)
在这种情况下,不应该有downloadable_resources
表。您的书籍和下载表都应该声明他们需要的所有字段。