Model inheritance

Hi ROM community,

Could you just give me a hint where I have to look on to implement a simple inheritance based on a attribute. To keep things simple, lets say I want to have a SimpleProject and ComplexProject and the inheritance attribute would be a type.

What is more interesting:

  • SimpleProject has a value attribute which is just a String.
  • ComplexProject has a value attribute which is a hash and serialized to JSON.

So then if I want to fetch projects:
projects.to_a
it will return me instances of SimpleProject or ComplexProject based on the type attribute.

Do I need to implement that by hand using a map method inside users reposioty or ROM provides any predefined methods for that or at least guidelines how to do it in the most efficient way?

PS.
I am new to the ROM, I used DataMapper even before diving in to the Rails and ActiveRecord.
Now ROM seems to be a really production ready solution.

You could do something like this:

require "rom-repository"
require "dry-struct"

config = ROM::Configuration.new(:sql, 'sqlite::memory')

config.gateways[:default].create_table(:users) do
  primary_key :id
  column :name, String
  column :type, String
end

class Users < ROM::Relation[:sql]
  schema do
    attribute :id, Types::Serial
    attribute :name, Types::String
    attribute :type, Types::Strict::String.enum('User', 'Admin')
  end
end

config.register_relation(Users)

config.mappers do
  register(:users,
    sti: -> users {
      users.map { |tuple| Object.const_get(tuple[:type]).new(tuple) }
    }
  )
end

container = ROM.container(config)

module Types
  include Dry::Types.module
end

class User < Dry::Struct
  attribute :id, Types::Int
  attribute :name, Types::String
end

class Admin < User
end

class UserRepo < ROM::Repository[:users]
  commands :create

  def all
    users.map_with(:sti).to_a
  end
end

repo = UserRepo.new(container)

repo.create(name: 'Jane', type: 'Admin')
repo.create(name: 'John', type: 'User')

repo.all
# [#<Admin id=1 name="Jane">, #<User id=2 name="John">]