Kashia is proud to present you this little tip:

Developing Flexible Og Applications

Tags: og

This tip is modeled after ideas on the Mailing List, in response to the given quotes:

In the Og/Nitro context would that mean that my web site would have a
Blog application, a Wiki application, a cookbook application and (say) a forums app. Each of those four applications would be in separate data-silos.

Ok, lets say we have these applications. For complete abstraction I will run all applications completely independend on a webserver.

5 tables in the DB at first:

  • oguser
  • ogblogpost
  • ogwikipage
  • ogcookbookpage
  • ogforumpost

lets build those:

$ cat blog/models/blog.rb

class BlogPost
   property :title, String
   property :text, String
 
   belongs_to User
end

$ cat cookbook/models/cookbook.rb

class CookbookPage
   property :recipe, String
   property :text, String
   belongs_to User
end

$ cat forum/models/forum.rb

class ForumPost
   is NestedSets # a little more advanced `has_many :answers, ForumPost`
 
   property :title, String
   property :text, String
   belongs_to User
end

We both know that I don't want four user_registration tables, so each application presumably shared the user_registration table. That is just good Object oriented decomposition.

$ cat common/models/common.rb

class User
   property :name, String
   prop_read :pass, String
end

Which gets included in every other application. (Later on, on how to do that with different 'silos'). Right now, all applications run on the same silo.

Now, all the applications have a run.rb (i.e. cookbook/run.rb) which has the Og.setup in it (which handles the connection to the silo).

In a few years or months time someone will get a good idea that uses one
or more data-silos in some brilliant way! The difference between a 'clean' data model and persistent entity-relations (which is what OG::managed_classes is), will be the time and money it costs to make the good idea work and the number of extra bugs due to the good idea spread
over the five applications (four plus one).

I'm now the one that gets the brilliant idea! I'm building a social network application (Yes, I'm sooo Web 2.0 ;D (just kidding :P)) which is based on my previous work on the other applications. I'm using the cookbook and the forum posts to match the taste of everyone to get information what is the most popular meal in my community.

$ cat info/models/info.rb

require '../common/models/common.rb'
require '../forum/models/forum.rb'
require '../cookbook/models/cookbook.rb'
 
class Statistics
   property :description, String
   has_one CookbookPage
   has_many User # this has effects on Users, it adds a column
                 # which won't be seen by the other applications
end

What I have now, is a different view on the DB of what I had before, but while the data will physically exist in the same bucket of information, it will only be readable by the statistics app, because only it has the access (by using the Og Classes).

What I did now, is, reusing the readily existing data to rapidly build another application.

If now the data would persist in "different" data-silos, meaning other DBs or stores (like perhaps "Madeleine", which is a pure Ruby object store).

I would do the following, which is also done pretty fast:

$ cat info/models/info.rb

require '../common/models/common.rb'
$userstore = Og.setup()
require '../forum/models/forum.rb'
$forumstore = Og.setup()
require '../cookbook/models/cookbook.rb'
$cookbookstore = Og.setup()
 
class Statistics
   property :description, String
   has_one CookbookPage
   has_many User # this has effects on Users, it adds a column
                 # which won't be seen by the other applications
end
$infostore = Og.setup()

The Og.setup stuff are just copy/pastes from the applications where they come from, one may even set up a special [info]/model/connector.rb which has that Og.setup() readily available (good idea takes note).

We now have 4 stores with data in it. We actually don't need the global variables to them, they're not needed anyway. All I have to take care of that the right Class ends up in the right store, which we have done by sequentially call Og.setup with the right parameters and to require the right Classes right above them to avoid any unessessary troubles.

What we have, after we leave the 4 stores (without knowing about the global variables) is 4 object-sources which are ready to be used by the current application, no need to know about anything else in here.

Now in our glorious information hunting application we do the rest, like linking the forum posts to the cookbook by maybe running a CRM114 Bayesian Markovian Discriminator to classify every message, which is left as a programming exercise to the reader

This approach is imo very fast, almost can't be beaten by any other means since there is no recreation needed, all is there, ready to use, just make the right connections between programs.

(Side note: This approach can be used for the User table as well for each individual application, if they can't be in a single store together.)

To make it more clear, on how Og-Classes end up in different stores, observe:

class Bar
  property :name, String
end
$psql = Og.setup(:store => :psql, :name => "test")

class Foo
  property :name, String
end
$sqlite = Og.setup

puts $psql.managed_classes # => [Bar]
puts $sqlite.managed_classes # => [Foo]

This means, after each Og.setup call, Og looks for Classes it can handle, in this example Bar would end up as a table in the 'test' database of PostgreSQL, Foo would end up as a table in data.db, which is the standard Sqlite database if nothing is given.

I hope anyone finds that little tutorial at least entertaining to read