实现抽象基础模型类,Rails Way™

Mar*_*tuc 14 inheritance activerecord abstract-class ruby-on-rails sti

我有一个共享许多属性的Book and Download模型,因此我的目标是从DownloadableResource模型继承公共属性.
看看STI,但我改为抽象基础模型类:

  • 楷模:

    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
    
    Run Code Online (Sandbox Code Playgroud)
  • 迁移:

    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
    
    Run Code Online (Sandbox Code Playgroud)

迁移后,当我创建一个新书时,结果远非预期:

> Book.new
=> #<Book id: nil, cover_url: nil, authors: nil, created_at: nil, updated_at: nil> 
Run Code Online (Sandbox Code Playgroud)

有人可以说明如何实现抽象基础模型类技术,以便ActiveRecord模型可以通过继承共享公共代码,但是可以持久化到不同的数据库表吗?

Jiř*_*šil 11

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

  • 你不需要这张downloadable_resources桌子
  • Book.table_name打印books而不是downloadable_resources

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

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

为了解决你的问题,我可能会采用不同的方法.我会创建另一个称为DownloadableContent自包含的模型.它将包括验证,表将具有所有属性.最后模型Book和模型Download将具有多态has_one关系DownloadableContent.

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


Fin*_*arr 5

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

  • 为什么?是什么让这个案子不适合继承?以及如何确定何时值得继承以及何时不继承? (2认同)