Tim
Tim

Reputation: 60110

DataMapper subclassing & many-to-many self-referential relationships

I'm building a small Ruby application using DataMapper and Sinatra, and I'm trying to define a basic blog model:

I'm running into trouble getting the self-referential relation between comments going due to the fact that each Comment belongs_to a Post. My classes right now look like this:

class User
  include DataMapper::Resource
  property :id, Serial
  property :username, String
  property :password, String

  has n, :post
end
class Post
  include DataMapper::Resource
  property :id, Serial
  property :content, Text

  belongs_to :user

  has n, :comment
end
class Comment
  include DataMapper::Resource
  property :id, Serial
  property :content, Text

  belongs_to :user
  belongs_to :post
end

I'm following the guide at Associations and building a new object (CommentConnection) to link two comments together, but my issue is that each subcomment shouldn't belong to a Post as implied by the Comment class.

My first instinct was to extract out a superclass for Comments, so that one subclass could be "top-level" and belong to a post, while the other kind of comment belongs to another comment. Unfortunately, when I do that I run into issues with the comment IDs becoming null.

What's the best way to model this kind of recursive comment relationship in DataMapper?

Upvotes: 0

Views: 907

Answers (1)

Joe Harris
Joe Harris

Reputation: 14035

What you need is a self referential join in Comments, e.g., each Comment can have a parent comment. Try the following:

class Comment
  include DataMapper::Resource
  property :id, Serial
  property :content, Text

  has n, :replies, :child_key => [ :original_id ]
  belongs_to :original,  self, :required => false #Top level comments have none.
  belongs_to :user
  belongs_to :post
end

This will allow you to have replies to any given comment, although accessing them may get a little nasty (slow) if the volume gets high. If you get this working and want something more sophisticated you could look at nested sets, I believe there is a nested sets plugin for DataMapper but I haven't used.

Upvotes: 5

Related Questions