DataMapper Associations Dilemma

I’ve been working with DataMapper and trying to use associations between models Project and Task. I had the models in separate files project.rb and task.rb. When I tried associating them with each other I got the following error:

Cannot find the parent_model Project for Task in project (NameError)

I gathered this was caused by project.rb requiring task.rb and vice versa, since the association worked fine if I just put the require in one of the files. Here’s the code:

project.rb

require 'dmconfig'
require 'task'

class Project
  include DataMapper::Resource
  property :id,         Serial
  has n,                :tasks
end
    
DataMapper.finalize
DataMapper.auto_upgrade!

task.rb

require 'dmconfig'
require 'project'

class Task
  include DataMapper::Resource
  property :id,         Serial
  belongs_to            :project
end

DataMapper.finalize
DataMapper.auto_upgrade!

dmconfig.rb

require 'rubygems'
require 'dm-core'
require 'dm-migrations'

DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(:default, 'sqlite://' +
                 Dir.pwd + '/taskmanager.db')

If I removed the association from one of the files it worked fine, at least from one direction:

require 'dmconfig'
    
class Project
  include DataMapper::Resource
  property :id,         Serial
end

DataMapper.finalize
DataMapper.auto_upgrade!

If I want the association to work from both directions is the only reasonable solution to just put both classes in the same file? Or is there a way that I can keep them separated and still manage it?

Well, as it turns out, there’s a better way to set these files up. Here’s the revised version:

project.rb

class Project
  include DataMapper::Resource
  property :id,         Serial
  has n,                :tasks
end

task.rb

class Task
  include DataMapper::Resource
  property :id,         Serial
  belongs_to            :project
end

dmconfig.rb

require 'dm-core'
require 'dm-migrations'
require 'project'
require 'task'

DataMapper::Logger.new($stdout, :debug)
DataMapper.setup(:default, 'sqlite://' +
                 Dir.pwd + '/taskmanager.db')
DataMapper.finalize
DataMapper.auto_upgrade!

All of the required files are loaded in the config file. Also note that finalize should only be called when all of the necessary models have been loaded, not after each model individually. I have some concerns about how this will affect resources when there are more models, not all of which are necessarily going to be used at the same time, but I can’t seem to put it into concrete terms, so we’ll let it fly for now. It’s unlikely that the resource consumption of a list manager will ever reach something worthy of concern anyway.

Tags: , ,

Leave a Reply

You must be logged in to post a comment.