Roy Wright <roywrig...@gmail.com> writes: > On Sep 13, 2009, at 4:37 AM, Chris Hoeppner wrote: > >> >> Hey, >> >> I'm building a small wiki "engine" using DataMapper to handle the >> persistence. Let me explain my layout, and the riddle I encountered: >> >> * Everything is a Page. >> * Pages can have many childs, but only one parent. >> * Pages with the same parent need to have distinct labels (titles, >> names...) >> >> My first thought was adding :key => true to parent_id and label, but >> the >> next second I thought that why I'd have all this as PK. Also, it would >> force me to have *every* page parented somewhere. I could of course >> add >> a Page called Wiki as root, or have root Pages come with a parent_id >> of >> zero... >> >> This is where I thought I'd ask a bit around. I'm sure you DM wizards >> will have a magic answer, or at least a hint in the right direction. >>
> Maybe change the third requirement to be: > > * Pages must have distinct labels (titles, names...) > > then make the labels unique. The ideal situation is that page names can be duplicate as long as they are not siblings, so you can have a Foo page child of Bar, and another Foo page, child of Baz. After all +/wiki/bar/foo+ is distinct to +/wiki/baz/foo+, right? I'm nobody to tell my users where and how to name their pages. Things should just work and not fail in cryptic ways. A user does not need to know how I manage my IA. I have made up a fairly hacky way of doing this. Here goes: class Page include DataMapper::Resource property :id, Serial property :parent_id, Integer, :unique_index => :path, :default => 0 property :label, String, :unique_index => :path # Revisions handle the Page's content. # To access the latest thing: # @page.revisions.last # or use the #body helper: # @page.body # which yields the latest revision's content. has n, :revisions, :class_name => 'Wiki::Revision' # Can have one parent, and many child Pages. belongs_to :parent, :class_name => 'Wiki::Page', :child_key => [:parent_id] has n, :children, :class_name => 'Wiki::Page', :child_key => [:parent_id] end I have left out all methods, for simplicity. I basically have methods for walking the hierarchy, some string transformations, etc, but that's out of the scope now. As you can see, I've defined a property, :parent_id, with the same name as the :child_key used for the self-referential relation. I actually wrote this jokingly, but in awe discovered it to work. As this is now, it defines a compound unique index on the label and parent. Here is the method I use to retrieve pages based on their path: def self.for_path(path) # Special page RootIndex return first(:label => "RootIndex") if path == "" leaf = path.split("/").last # Select all pages that match +leaf+, and then check the +#path+ # method to see if any matches the +path+ argument. pages = all(:label => leaf.camel_case) matches = pages.select { |p| p.path == path} # This returns the first array element. IF there are more, they # are ignored. matches.first || nil end It first declares a special case for a "magic" root index page, and then proceeds to work on the given path. It finds all pages who's :label matches the end component of the path, and then checks the #path on each page to see if it matches. The path is built as follows: def path @path ||= parents.map {|p| p.label.snake_case }.join("/") / label.snake_case end where #parents returns an array of ancestors, in the correct order (root page first, and it's childs in descending order). The whole endeavour is still missing some specs for certain cases, like root pages (pages with no ancestors), but IMHO it's heading in the right direction. You're welcome to prove me wrong, of course =) > For a wiki, I'd also question your second requirement. IMO, pages > should have n:n relationships. Page relationships fill the role of categories. Everything being a page greatly simplifies things. A page with no content renders a child index. A page with content and childs will show it's childs at the bottom, or in a sidebar, etc. If you think about it, this is a pretty sane way of doing it. Or would you rather have abstract categories and pages associated with them to render stuff? Thought so. -- Chris Hoeppner El que nació para melón, nunca llegará a sandía. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "DataMapper" group. To post to this group, send email to datamapper@googlegroups.com To unsubscribe from this group, send email to datamapper+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/datamapper?hl=en -~----------~----~----~----~------~----~------~--~---