Hi all, I would like to discuss a design idea I have in mind with you, in order to get critical feedback. ActiveRecord supports single table inheritance(STI) "per se", BUT you must add all possible instance variables(properties) of all subclasses to the "base table"(as columns). I would like to circumvent this restriction. Say we have a class AbstractGenericThing < ActiveRecord:Base has_many :properties end In order to support STI the abstract_generic_things-table must have a :type column. Next comes the Property class class Property < ActiveRecord:Base belongs_to :GenericObject end The properties table has the following columns :key, :string :value, :string -> hence we have a simple key-value-pair table. Now any class which subclasses AbstractGenericThing inherits the properties-array. A subclass can have as many properties as it requires. So far we can have concrete (sub)classes for our concrete domain objects but the property handling is not yet "intuitive". Enter ''method_missing''-hook class AbstractGenericThing # all methods which are not defined are handled as # properties def method_missing(methodname, *args) methodnameStr = methodname.to_s if (methodnameStr.include? "=") # it''s a setter! # remove the trailing methodnameStr.chop! return setProperty(methodnameStr, args[0]) else # it''s a getter! return getProperty(methodnameStr) end end # helper method for setting the given property def setProperty(propertyName, value) property = self.properties.find(:first, :conditions => [ "name = ?", propertyName]) if (property.nil?) # Looks like the property does not yet exist. # Create it and set the value... property = Property.new(:name => propertyName, :value => value) # add this new property to my properties self.properties << property # safe? else # change the property''s value p "modifying property" property.value = value property.save #self.safe end end # helper method for getting the value of the given property def getProperty(propertyName) # there should be(at most) one property = properties.find(:first, :conditions => [ "name = ?", propertyName]) if (property.nil?) return nil else return property.value end end end Now we can dynamically "add" properties to our conrete objects(classes). E.g.: class Person < AbstractGenericThing end person = Person.new person.GivenName = "John" person.Name = "Smith" person.GivenName>> Johnperson.Name>> Smith... Persistence works as expected, hence I am inclined to go with this design. BEFORE I do I would like to hear what you think? What am I missing(apart from the semantics I loose as all properties are stored as strings)? Thanks for any critical input! Clemens -- Posted via http://www.ruby-forum.com/.
On Sun, Jul 02, 2006 at 11:55:13AM +0200, Clemens Wyss wrote: } Hi all, } I would like to discuss a design idea I have in mind with you, in order } to get critical feedback. } } ActiveRecord supports single table inheritance(STI) "per se", BUT you } must add all possible instance variables(properties) of all subclasses } to the "base table"(as columns). I would like to circumvent this } restriction. [...] } Persistence works as expected, hence I am inclined to go with this } design. } BEFORE I do I would like to hear what you think? What am I missing(apart } from the semantics I loose as all properties are stored as strings)? Please take a look at http://redcorundum.blogspot.com/2006/07/ror-additional-attributes-with-sti.html I''d been meaning to post about it for a while, and you got me to actually write it up. } Thanks for any critical input! } Clemens --Greg
Gregory Seidman wrote:> On Sun, Jul 02, 2006 at 11:55:13AM +0200, Clemens Wyss wrote: > } Hi all, > } I would like to discuss a design idea I have in mind with you, in > order > } to get critical feedback. > } > } ActiveRecord supports single table inheritance(STI) "per se", BUT you > } must add all possible instance variables(properties) of all subclasses > } to the "base table"(as columns). I would like to circumvent this > } restriction. > [...] > } Persistence works as expected, hence I am inclined to go with this > } design. > } BEFORE I do I would like to hear what you think? What am I > missing(apart > } from the semantics I loose as all properties are stored as strings)? > > Please take a look at > http://redcorundum.blogspot.com/2006/07/ror-additional-attributes-with-sti.html > > I''d been meaning to post about it for a while, and you got me to > actually > write it up. > > } Thanks for any critical input! > } Clemens > --GregDear Greg, thanks for posting your thoughts about this issue. Your solution brings in mainly two improvements over mine. 1) Replacing ''method_missing'' by meta prgramming(''additional_attribute'') This is definitely an improvement. Not only in performance(which might not be an issue) but mainly due to explicitness. Though this approach is applicable for the non-serialize-solution too. Or am I wrong? 2) Persisting properties/attributes with ActiveRecord''s serialize(yaml) If you are absolutely sure that the properties are not needed for any (Db-)lookup I agree that the serialze-approach is way better(performance and simplicity). In my case I might need a lookup some properties so I am not sure whether I should switch to serialize. Regards Clemens -- Posted via http://www.ruby-forum.com/.
On Jul 02, 2006, at 10:55 am, Clemens Wyss wrote:> I would like to discuss a design idea I have in mind with you, in > order > to get critical feedback. > > ActiveRecord supports single table inheritance(STI) "per se", BUT you > must add all possible instance variables(properties) of all subclasses > to the "base table"(as columns). I would like to circumvent this > restriction.Hi Clemens I was going to reply to you earlier - I won''t offer any feed back because it seems Greg has given you everything you need. What I''m curious about, though, is why you brought this up in the context of STI? Right now I''m very interested in solving both the missing information and inheritance problems. Your problem seems separate from inheritance though, because your solution allows a class to have any properties. What was it that made you need these arbitrary properties anyway? Actually I''ve thought of one useful thing I can pass on. Our company''s wiki runs on XWiki, and this has a very basic schema. What they do is use one table per database type - I believe they are named something like ''xwikistrings'', ''xwikiintegers'', ''xwikibooleans'', etc. This way you get the flexibility without losing the ability to do things "SELECT values FROM properties WHERE value > 3" efficiently. Ashley
Ashley Moran wrote:> On Jul 02, 2006, at 10:55 am, Clemens Wyss wrote: > >> I would like to discuss a design idea I have in mind with you, in >> order >> to get critical feedback. >> >> ActiveRecord supports single table inheritance(STI) "per se", BUT you >> must add all possible instance variables(properties) of all subclasses >> to the "base table"(as columns). I would like to circumvent this >> restriction. > > Hi Clemens > > I was going to reply to you earlier - I won''t offer any feed back > because it seems Greg has given you everything you need. What I''m > curious about, though, is why you brought this up in the context of > STI?I first had my Db schema which had the properties table. Then I thought it would be nice if I could still have concrete classes for my various domain objects. I then came across STI in the AWDwR-book but didn''t want to give up the "flexibility" in the Db schema. This lead me to my proposal.> Right now I''m very interested in solving both the missing > information and inheritance problems. Your problem seems separate > from inheritance though,As mentioned above I still want to have specific(concrete) classes for my domain objects, but I do not yet know all properties these classes will have AND I don''t want to change the Db-schema everytime a new domain object(and/or) property for domain object comes up. Maybe I am looking too much into the future(not really XP''ish, I know).> because your solution allows a class to have > any properties. > What was it that made you need these arbitrary > properties anyway?see my answers above. Also note in my last post that I admit that Greg''s declarative(meta-programming) approach is "better". Greg''s approach is less "arbitrary", which is fine for my project, too.> > Actually I''ve thought of one useful thing I can pass on. Our > company''s wiki runs on XWiki, and this has a very basic schema. What > they do is use one table per database type - I believe they are named > something like ''xwikistrings'', ''xwikiintegers'', ''xwikibooleans'', > etc. This way you get the flexibility without losing the ability to > do things "SELECT values FROM properties WHERE value > 3" efficiently. > > AshleyAt the moment I do not see any need for absolutely needing to know the type of my properties. I am really happy getting this kind of critical feedback. It makes me rethink and maybe even reject my decision, which is ok in the beginning of a project ;-) Regards Clemens -- Posted via http://www.ruby-forum.com/.
> As mentioned above I still want to have specific(concrete) classes for > my domain objects, but I do not yet know all properties these classes > will haveuhhuh..another ActiveRDF candidate. theres really a lot of reading out there on the subject, but for starters, id try the ActiveRDF docs[3], the pdf from Obie Fernandez ''Deep Integration of Ruby with Semantic Web Ontologies''[2], and a page from the W3C (concepts and abstract syntax)[1]. 1. http://www.w3.org/TR/2004/REC-rdf-concepts-20040210/ 2. http://gigaton.thoughtworks.net/~ofernand1/DeepIntegration.pdf 3. http://activerdf.org/manual/manual.html> I am really happy getting this kind of critical feedback. It makes me > rethink and maybe even reject my decisionno!! go with your instincts. just figure out a way to make them happen.. c
Hi! On Jul 2, 2006, at 12:21 PM, Clemens Wyss wrote:> Gregory Seidman wrote: >> On Sun, Jul 02, 2006 at 11:55:13AM +0200, Clemens Wyss wrote: >> } Hi all, >> } I would like to discuss a design idea I have in mind with you, in >> order >> } to get critical feedback. >> } >> } ActiveRecord supports single table inheritance(STI) "per se", >> BUT you >> } must add all possible instance variables(properties) of all >> subclasses >> } to the "base table"(as columns). I would like to circumvent this >> } restriction. >> [...] >> } Persistence works as expected, hence I am inclined to go with this >> } design. >> } BEFORE I do I would like to hear what you think? What am I >> missing(apart >> } from the semantics I loose as all properties are stored as >> strings)? >> >> Please take a look at >> http://redcorundum.blogspot.com/2006/07/ror-additional-attributes- >> with-sti.html >> >> I''d been meaning to post about it for a while, and you got me to >> actually >> write it up. >> >> } Thanks for any critical input! >> } Clemens >> --Greg > > Dear Greg, > thanks for posting your thoughts about this issue. Your solution > brings > in mainly two improvements over mine. > > 1) Replacing ''method_missing'' by meta prgramming > (''additional_attribute'') > This is definitely an improvement. Not only in performance(which might > not be an issue) but mainly due to explicitness. Though this > approach is > applicable for the non-serialize-solution too. Or am I wrong? > > 2) Persisting properties/attributes with ActiveRecord''s serialize > (yaml) > If you are absolutely sure that the properties are not needed for any > (Db-)lookup I agree that the serialze-approach is way better > (performance > and simplicity). In my case I might need a lookup some properties so I > am not sure whether I should switch to serialize. > > Regards > ClemensClemens- If you use ferret and acts_as_ferret for your db searches then you can define a custom .to_doc method in your models that hints to ferret how to index and search your serialized attributes. This lets you use nice serialization for meta data and stuff that changes too often to go in the db. And you still get full text and fuzzy text search on these serialized attributes. Cheers- -Ezra
On Jul 02, 2006, at 10:30 pm, Clemens Wyss wrote:> I first had my Db schema which had the properties table. Then I > thought > it would be nice if I could still have concrete classes for my various > domain objects. I then came across STI in the AWDwR-book but didn''t > want > to give up the "flexibility" in the Db schema. This lead me to my > proposal.Clemens Is this an existing schema you''ve inherited, or just your first draft at a new project?> As mentioned above I still want to have specific(concrete) classes for > my domain objects, but I do not yet know all properties these classes > will have AND I don''t want to change the Db-schema everytime a new > domain object(and/or) property for domain object comes up. Maybe I am > looking too much into the future(not really XP''ish, I know).Obviously without going into the requirements of your project I can''t say what would suit you best. But I approach database design as a mapping of business (or personal) requirements to facts. So if I have a business need (say a legal requirement) to store a date of birth of (say) an employee, then in it goes, as a specific column. Properties as rows rather than columns strike me as more useful for lookups rather than general queries. IE it''s easy to get all the properties of a given employee, but hard to write queries like "Find all managers more than 10 years older than the youngest employee they supervise" (or something less contrived). Because data tends to outlive applications, I prefer to go with the design that facilitates ad-hoc queries. As for XP, have you tried continuous integration? I''ve never done it with Ruby/Rails but I believe there''s a tool called DamageControl. CI lets you change the database as much as you like and still have absolute confidence it will work when you deploy live. Used with Migrations it should give you XP flexibility with old-fashioned stability. (I believe that database CI is as important as unit testing.)> see my answers above. Also note in my last post that I admit that > Greg''s > declarative(meta-programming) approach is "better". Greg''s approach is > less "arbitrary", which is fine for my project, too.I like that solution from the Ruby side, but not the database side. If I was going to use this property-based idea, I''d marry the two, and take your separate property table but use the explicit "additional_attribute :foo, :bar" metaprogramming to create the Ruby attributes. Just for comparison, here''s a similar solution to a problem that cropped up at work. I''ve only just convinced my boss to start using Rails, and he set one of our developers on to this small project for calculating online IT quotations. Basically, we want the available components for a quote (eg photocopiers, phones, faxes, whatever they want to sell) to be determined from the database, and have the GUI driven by the records it finds. But we don''t want to have to duplicate all that information in the model class either. So what I suggested is to make a Calculation class that subclasses OpenStruct, and add an "identifier" column into the component records that will be the Ruby attribute name. The neat thing about that is that you can use Rails'' block HTML form assignment to construct a whole model class. Then the code looks something like this: class Calc < OpenStruct def calc total = 0 if self.respond_to?(:num_photocopiers) total += <GET PHOTOCOPIER PRICE SOMEHOW> * self.num_photocopiers end total end end In fact, simple cases like that could be done even more elegantly by adding a boolean "simple" attribute to the database, that indicated to the code it could do a simple PRICE * QTY calc - it''s only the case where one item implicitly requires ordering one or more other parts that you need to write extra calculation rules. While it''s not completely database driven, it''s got us 50% of the way there with VERY little coding at all. (I''m not sure the developer gets how it works yet, but soon he will have an AHA! moment and join the metaprogramming crowd!) This of course is a different problem to yours but I thought I''d share it for comparison.> At the moment I do not see any need for absolutely needing to know the > type of my properties.What better reason for making sure you record them ;o) (See above for my obsession with making ad-hoc queries as easy as possible).> I am really happy getting this kind of critical feedback. It makes me > rethink and maybe even reject my decision, which is ok in the > beginning > of a project ;-)No probs. I don''t have much experience using Rails, but I''m ok with Ruby and databases. I''ve seen, though, that mistakes in the database generally stay there forever. Hopefully unit testing will make Rails apps suffer less from this. I''ve seen really hideous things in databases, and when I ask why we have a redundant column storing inconsistent data with no key constraints defined on it, the answer usually goes "no idea, but it works and who knows how many features will break if we remove it". Ashley