[ANN] inherits_from: Multiple table inheritance

Hey guys,

I just implemented very simple and primitive class table inheritance in
ActiveRecord. The goal is for this to become mature enough to become a
true feature in Rails. Check it out here:

http://[email protected]/svn/inherits_from

Hereâ??s how it looks in action:

create_table “books”, :force => true do |t|
t.column “product_id”, :integer
t.column “pages”, :integer
t.column “author”, :string
end

create_table “products”, :force => true do |t|
t.column “name”, :string
t.column “price”, :integer
t.column “type”, :string
end

create_table “videos”, :force => true do |t|
t.column “product_id”, :integer
t.column “minutes”, :integer
t.column “starring”, :string
end

class Product < ActiveRecord::Base
end

class Book < ActiveRecord::Base
inherits_from :product
end

class Video < ActiveRecord::Base
inherits_from :product
end

Book.create(:name => “Agile Development with Rails”, :pages => 350)
Video.create(:name => “Twilight Zone Season 1”, :minutes => 490)

Book.find(1).name => “Agile Development with Rails”

Note: this plugin is not production ready. Iâ??m hoping some people who
are much smarter than me will send me patches to make it primetime.
Known bugs:

* Inherited column validation/error handling does not currently work
* Book.find_by_name() (inherited column) does not work
* Only basic attributes are passed along right now

Feel free to send me any comments to ray @ this domain (raylucke.com).

I’ll be posting updates on my blog as well.

Regards,

Raymond W. Lucke IV
http://blog.raylucke.com/

Hi!

On Jul 3, 2006, at 5:07 PM, Raymond L. wrote:

Feel free to send me any comments to ray @ this domain (raylucke.com).

I’ll be posting updates on my blog as well.

Regards,

Raymond W. Lucke IV
http://blog.raylucke.com/

Raymond-

This looks pretty cool and I would love to play with it.

Unfortunately your link you posted here and on your blog requires a
password apparently. Can you tell me what I need to do to download
the plugin?

Thanks-
-Ezra_______________________________________________
Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

Hi Ezra,

Try entering guest as the username and sending a blank password. That
should work.

Regards,

Ray

Ezra Z. wrote:

Hi!

On Jul 3, 2006, at 5:07 PM, Raymond L. wrote:

Feel free to send me any comments to ray @ this domain (raylucke.com).

I’ll be posting updates on my blog as well.

Regards,

Raymond W. Lucke IV
http://blog.raylucke.com/

Raymond-

This looks pretty cool and I would love to play with it.
Unfortunately your link you posted here and on your blog requires a
password apparently. Can you tell me what I need to do to download
the plugin?

Thanks-
-Ezra_______________________________________________
Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

On Tuesday 04 July 2006 04:40, Josh S. wrote:

How interesting! Â I’m impressed you were able to get this to work in as
little code as you did. Pretty good for a science project. However, I
think your approach has some serious limitations and you may be right
about it being fundamentally flawed.

I haven’t seen the code yet but Class TI is a feature I’d really like in
Rails. There’s a chance I’ll get to do some work on it at work so I was
hoping to see someone else have a go for inspiration.

One issue I’ve wondered about is when you have non-mutually exclusive
subclasses. Eg

            Worker
     (def work; ...; end)
          /        \
  Manager            First Aider

(def shout; …; end) (def heal; …; end)

Should entries be allowed in both the managers and first_aiders
tables? If
so I guess you have to use mixins to allow extra code funcionality from
both
subcategories.

By the way, I think in a typical ClassTI design, the PKs of the segments
are synced across tables, so you don’t need to keep a FK for the parent
record in the child record.

I assume by this you mean that you don’t have auto-incremented surrogate
keys
in the subclass tables, and the primary key is manually set to the same
value
as the corresponding superclass entry? I think that’s what I’ve seen
before.

My big gripe with ClassTI is that you have to do a select or join for
each level of inheritance to get a single object from the database. That
doesn’t make it a non-starter, but it’s a pretty big performance hurdle
to get over.

If you don’t like the complexity of the joins, don’t forget you can
define
views to represent the “whole” subclass.

I think the performance hit of joins is often over-estimated. Fetching
everything in the combined join will take longer than a single table,
but
most queries only involve a subset of data. (Also some database servers
can
cache the result of joins.) Generally it’s probably better to design
for
simplicity first, and only change your design for performance if really
necessary.

I imagine the worst thing you could do with a Class TI design is to
iterate
over the entities, fetching each one in turn. That would make the app
query
every subclass table to find what class it belongs to.

Have you looked into the Concrete Table Inheritance pattern? I think
that would be more useful for Rails type apps, though it could be a
polymorphic nightmare doing a find(:all) on the parent class!

I haven’t given it THAT much thought, but I’m not too fond of Concrete
TI.
Mainly because:

  • it complicates table design
    (changes must be made to multiple tables)
  • it makes it harder to turn one entity type into another
    (in Class TI, just insert or delete a sub-entity record)
  • it completely rules out multi-class entities
    (unless you want really nasty redundancy in the data)

Let me know your thoughts everyone hopefully I’ll be able to join in the
Class
TI effort some time.

Ashley

Raymond L. wrote:

I just implemented very simple and primitive class table inheritance in
ActiveRecord. The goal is for this to become mature enough to become a
true feature in Rails. Check it out here:

http://[email protected]/svn/inherits_from

Raymond W. Lucke IV
http://blog.raylucke.com/

How interesting! I’m impressed you were able to get this to work in as
little code as you did. Pretty good for a science project. However, I
think your approach has some serious limitations and you may be right
about it being fundamentally flawed.

By the way, I think in a typical ClassTI design, the PKs of the segments
are synced across tables, so you don’t need to keep a FK for the parent
record in the child record.

My big gripe with ClassTI is that you have to do a select or join for
each level of inheritance to get a single object from the database. That
doesn’t make it a non-starter, but it’s a pretty big performance hurdle
to get over.

Have you looked into the Concrete Table Inheritance pattern? I think
that would be more useful for Rails type apps, though it could be a
polymorphic nightmare doing a find(:all) on the parent class!


Josh S.
http://blog.hasmanythrough.com

Ashley,

It would seem to me that you could accomplish a much of what you’re
talking about with something that looks like this:

class Worker < ActiveRecord::Base
has_one :manager
has_one :first_aider

def manager?
!manager.nil?
end

def first_aider?
!first_aider.nil?
end
end

class Manager < ActiveRecord::Base
belongs_to :worker
end

class FirstAider < ActiveRecord::Base
belongs_to :worker
end

john = Worker.find_by_name(“john”)

John the manager will shout now if he is one.

john.manager.shout if john.manager?

John the first aider will heal if he is one.

john.first_aider.heal if john.first_aider?

In fact, using a method similar to what I did in my plugin, you can
create a proxy accessor if you really want to call john.shout and not
john.manager.shout.

One of the design goals of my plugin is functionality through a simple
means. If you notice, it’s really nothing more than an attribute proxy
method generator that iterates over the parent’s attributes. You could
theoretically even add something like this:

class Worker < ActiveRecord::Base
has_one :manager

alias_associated_attr(‘manager’, ‘shout’)

def manager?
!manager.nil?
end
end

steve = Worker.find_by_name(“steve”)
steve.shout if steve.manager?

I’m not sure if I quite answered your question here, but I guess my
point is that I don’t think you really need inheritance at all for the
scenario you pointed out above. It even can yield a bit cleaner code
sometimes when you can encapsulate the role-specific methods/attributes,
in this case for manager, in their own class.

Regards,

Ray

Ashley M. wrote:

On Tuesday 04 July 2006 04:40, Josh S. wrote:

How interesting! Â I’m impressed you were able to get this to work in as
little code as you did. Pretty good for a science project. However, I
think your approach has some serious limitations and you may be right
about it being fundamentally flawed.

I haven’t seen the code yet but Class TI is a feature I’d really like in
Rails. There’s a chance I’ll get to do some work on it at work so I was
hoping to see someone else have a go for inspiration.

One issue I’ve wondered about is when you have non-mutually exclusive
subclasses. Eg

            Worker
     (def work; ...; end)
          /        \
  Manager            First Aider

(def shout; …; end) (def heal; …; end)

Should entries be allowed in both the managers and first_aiders
tables? If
so I guess you have to use mixins to allow extra code funcionality from
both
subcategories.

By the way, I think in a typical ClassTI design, the PKs of the segments
are synced across tables, so you don’t need to keep a FK for the parent
record in the child record.

I assume by this you mean that you don’t have auto-incremented surrogate
keys
in the subclass tables, and the primary key is manually set to the same
value
as the corresponding superclass entry? I think that’s what I’ve seen
before.

My big gripe with ClassTI is that you have to do a select or join for
each level of inheritance to get a single object from the database. That
doesn’t make it a non-starter, but it’s a pretty big performance hurdle
to get over.

If you don’t like the complexity of the joins, don’t forget you can
define
views to represent the “whole” subclass.

I think the performance hit of joins is often over-estimated. Fetching
everything in the combined join will take longer than a single table,
but
most queries only involve a subset of data. (Also some database servers
can
cache the result of joins.) Generally it’s probably better to design
for
simplicity first, and only change your design for performance if really
necessary.

I imagine the worst thing you could do with a Class TI design is to
iterate
over the entities, fetching each one in turn. That would make the app
query
every subclass table to find what class it belongs to.

Have you looked into the Concrete Table Inheritance pattern? I think
that would be more useful for Rails type apps, though it could be a
polymorphic nightmare doing a find(:all) on the parent class!

I haven’t given it THAT much thought, but I’m not too fond of Concrete
TI.
Mainly because:

  • it complicates table design
    (changes must be made to multiple tables)
  • it makes it harder to turn one entity type into another
    (in Class TI, just insert or delete a sub-entity record)
  • it completely rules out multi-class entities
    (unless you want really nasty redundancy in the data)

Let me know your thoughts everyone hopefully I’ll be able to join in the
Class
TI effort some time.

Ashley

I propose a turnaround of your setup that makes this seem more “right”
to me, i’ll try it myself, though I’m only a week old ruby/rails newbie:

create_table “products”, :force => true do |t|
t.column “id”, :string
t.column “name”, :string
t.column “price”, :integer
t.column “type”, :string #this is either book|video
t.column “entity_id” :integer #this will be the id in the
corresponding “#{type}s” table
end

create_table “books”, :force => true do |t|
t.column “id”, :integer
t.column “pages”, :integer
t.column “author”, :string
end

create_table “videos”, :force => true do |t|
t.column “id”, :integer
t.column “minutes”, :integer
t.column “starring”, :string
end

class Product < ActiveRecord::Base
end

class Book < ActiveRecord::Base
inherits_from :product
end

class Video < ActiveRecord::Base
inherits_from :product
end

Book.create(:name => “Agile Development with Rails”, :pages => 350)
Video.create(:name => “Twilight Zone Season 1”, :minutes => 490)

Book.find(1).name => “Agile Development with Rails”
Video.find(1).name => “Twilight Zone Season 1”
Product.find(1).name => “Agile Development with Rails”
Product.find(2).name => “Twilight Zone Season 1”

On Wednesday 05 July 2006 16:06, Juan Felipe García wrote:

end
t.column “minutes”, :integer
class Video < ActiveRecord::Base
inherits_from :product
end

Book.create(:name => “Agile Development with Rails”, :pages => 350)
Video.create(:name => “Twilight Zone Season 1”, :minutes => 490)

Book.find(1).name => “Agile Development with Rails”
Video.find(1).name => “Twilight Zone Season 1”
Product.find(1).name => “Agile Development with Rails”
Product.find(2).name => “Twilight Zone Season 1”

Hmmm, I can see what you’re trying to do but I’m not sure it will work
well.
You lose Ruby class inheritance, so if you have a method in Product (say
Product#price_in_euros) it won’t be available to instances of Book and
Video.

Bear in mind that videos and books are a “nice” case, where the two
subclasses
are mutually exclusive. In the case of managers and first-aiders, a
person
could be both at the same time. I’m not sure if a class-table
inheritance
solution should allow this (or could allow this).

Watch out because “type” is a reserved column name that ActiveRecord
uses to
determine the class in single table inheritance. This has bit me
before.

The canonical way to manage the ID columns is to give each of the
subclass
tables non-autogenerated ID fields that match the auto-generated ID of
the
top level class.

I think the syntax is like this:

create_table “products”, :force => true do |t|
 # …column defs…
end

create_table “books”, :id => false do |t|
 t.column “id”, :integer # always refers to a value in table
“products”
 # …column defs…
end

create_table “videos”, :id => false do |t|
 t.column “id”, :integer # always refers to a value in table
“products”
 # …column defs…
end

If you’re new to Ruby then this is a very ambitious project! Although
it
should get you up to speed in no time. I recommending read chapters
22-24 of
the Pickaxe first though, so you understand Ruby inheritance thoroughly
(not
that I’m an expert- there are plenty of things in chapter 24 I need to
refer
to often).

Ashley

On Tuesday 04 July 2006 12:54, Raymond L. wrote:

  !manager.nil?

john.first_aider.heal if john.first_aider?
You could do this, but the problem is that if each Worker has a Manager,
and
each Manager has a Manager, it would get very confusing calling, say,
john.manager_subclass.shout
john.manager.shout

In fact, using a method similar to what I did in my plugin, you can
create a proxy accessor if you really want to call john.shout and not
john.manager.shout.

One of the design goals of my plugin is functionality through a simple
means. If you notice, it’s really nothing more than an attribute proxy
method generator that iterates over the parent’s attributes. You could
theoretically even add something like this:

I had a look at last, and you’re right, you found a really
straightforward way
to do it. When I get a moment I’ll try it out.

steve = Worker.find_by_name(“steve”)
steve.shout if steve.manager?

I’m not sure if I quite answered your question here, but I guess my
point is that I don’t think you really need inheritance at all for the
scenario you pointed out above. It even can yield a bit cleaner code
sometimes when you can encapsulate the role-specific methods/attributes,
in this case for manager, in their own class.

I can see your argument, but if I had multiple inheritance I’d like to
be able
to do this:

class Worker < ActiveRecord::Base
def message; “I work”; end
def shout; message; end
end

class Manager < ActiveRecord::Base
def message; “I manage”; end
end

class FirstAider < ActiveRecord::Base
def message; “I heal”; end
end

john = Worker.find_by_name(“John T Manager”)
john.shout => “I manage”

billy = Worker.find_by_name(“Billy F Aider”)
billy.shout => “I heal”

Of course it all goes to pot when Jack A Trader is both a Manager and a
First
Aider, when multiple inheritance turns ugly. Which makes me wonder if
it’s
worth even trying to support it, in ClTI

Another thing is that I don’t believe Rails supports reloading modules
in
development mode (please correct me if that isn’t true), which I assumed
would be the only way to implement it. If you started using separate
classes, then method overriding would have to be implemented manually,
and
it’s Ruby’s job to provide that.

My feeling right now is that it’s just not worth it, and the best
solution
would be single ClTI inheritance in ActiveRecord and some sort of
role-based
code in the app. I guess until I’ve had a go I won’t know how it works
out.

Thanks for your feedback

Ashley

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs