【问题标题】:Implementing Abstract Base Model Class, the Rails Way™实现抽象基模型类,Rails Way™
【发布时间】:2012-12-14 20:32:05
【问题描述】:

我有一个共享许多属性的 BookDownload 模型,所以我的目标是从 DownloadableResource 模型继承公共属性。
看过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 共享公共代码,但可以持久保存到不同的数据库表中?

【问题讨论】:

  • 一种方法是组合而不是继承。一些例子:rails-bestpractices.com/posts/17-extract-into-module
  • 附带说明,即使您使用两个结构相似的表,您至少可以通过首先创建仅包含其唯一字段的所有表然后执行类似[:books, :downloads].each do |table| change_table table do |t| t.text :description # ... end end

标签: ruby-on-rails activerecord inheritance abstract-class sti


【解决方案1】:

通过将模型声明为抽象,您实际上是在说没有基础表并且您希望允许子类化。这意味着:

  • 您不需要downloadable_resources
  • Book.table_name 打印 books 而不是 downloadable_resources

正如@Finbarr 已经提到的,这也意味着BookDownload 模型都需要在其表中包含所有属性。

那么这实际上有什么用呢?在我看来不是很多。您可以共享验证、范围等,但您可以通过包含自定义模块更轻松地实现所有这些。

为了解决您的问题,我可能会采用不同的方法。我将创建另一个名为DownloadableContent 的模型,该模型将是自包含的。它将包括验证,并且该表将具有所有属性。最后,模型BookDownload 将与DownloadableContent 模型具有多态has_one 关系。

您可以使用 STI 方法,但我通常不喜欢将所有自定义属性混合在一起。

【讨论】:

    【解决方案2】:

    在这种情况下不应该有downloadable_resources 表。您的书籍和下载表都应声明它们需要的所有字段。

    【讨论】:

    • 为什么?是什么让这种情况不适合继承?以及如何决定什么时候值得继承,什么时候不值得?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-03
    • 1970-01-01
    • 1970-01-01
    • 2021-01-31
    相关资源
    最近更新 更多