Domanda

I'm learning Sinatra (1.3.2) and chose to use DataMapper (1.2.0) as ORM and an in-memory SQLite (1.3.6) DB to start.
Two models, Books and Downloads, are sharing most attributes, so I looked into declaring a model for STI (Single Table Inheritance) in DataMapper. Reading the docs, this seems a piece of cake thanks to Types::Discriminator.

I abstracted all common ones into DownloadableResource:

class DownloadableResource
  include DataMapper::Resource

  property :id,           Serial
  property :created_at,   DateTime
  property :modified_at,  DateTime
  property :active,       Boolean,  default: true

  property :position,     Integer

  property :title,        String,   required: true
  property :url,          URI,      required: true
  property :description,  Text,     required: true

  property :type,         Discriminator
end

Following the example, I thought it's just as easy as specifying what needs to be extended:

class Book < DownloadableResource
  property :cover_url,    URI
  property :authors,      String,   required: true, length: 255
end

and

class Download < DownloadableResource
  property :icon_url,     URI
end

but this was giving me the following error:

DataObjects::SyntaxError: duplicate column name: id (code: 1, sql state: , query: ALTER TABLE "downloadable_resources" ADD COLUMN "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, uri: sqlite3::memory:?scheme=sqlite&user=&password=&host=&port=&query=&fragment=&adapter=sqlite3&path=:memory:)

while removing the id generated another (obvious) error:

DataMapper::IncompleteModelError: DownloadableResource must have a key to be valid

I got around this by adding include DataMapper::Resource to both Book and Download, and then Book needed a key to be valid, now looking like this:

class Book < DownloadableResource
  include DataMapper::Resource

  property :id,           Serial

  property :cover_url,    URI
  property :authors,      String,   required: true, length: 255
end

Same goes for Download, but now the issue is:

DataObjects::SyntaxError: duplicate column name: id (code: 1, sql state: , query: ALTER TABLE "books" ADD COLUMN "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, uri: sqlite3::memory:?scheme=sqlite&user=&password=&host=&port=&query=&fragment=&adapter=sqlite3&path=:memory:)

Starting to feel like I'm going in circles, what's the proper way to implement Single Table Inheritance in DataMapper?


PS: I have looked at

but I still have this problem.

È stato utile?

Soluzione

I would recommend this approach:

module DownloadableResource

  def self.included base
    base.class_eval do
      include DataMapper::Resource

      property :created_at,   DateTime
      property :modified_at,  DateTime
      property :active,       base::Boolean,  default: true

      property :position,     Integer

      property :title,        String,   required: true
      property :url,          base::URI,      required: true
      property :description,  base::Text,     required: true

      property :type,         base::Discriminator
    end
  end
end

class Book
  include DownloadableResource
  property :id, Serial
  # other properties
end

class Download
  include DownloadableResource
  property :id, Serial
  # other properties
end
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top