Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Model associations using DataMapper in separate files

I'm working with DataMapper and trying to use associations between models Project and Task. I have the models in separate files project.rb and task.rb. When I try associating them with each other I get the following error:

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

I gather this is caused by project.rb requiring task.rb and vice versa, since the association works fine if I just include it 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.auto_upgrade!
DataMapper.finalize

task.rb

require 'dmconfig'
require 'project'

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

DataMapper.auto_upgrade!
DataMapper.finalize

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 remove the association from one of the files it works fine, at least from one direction:

require 'dmconfig'

class Project
  include DataMapper::Resource
  property :id,         Serial
end

DataMapper.auto_upgrade!
DataMapper.finalize

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?

like image 201
lobati Avatar asked Dec 29 '22 05:12

lobati


1 Answers

You need to call finalize after you require all your models, not after each one. One of the things finalize does is sanity check your models, to make sure all the relevant models have been required. The application boot process, after requiring all the library files is an ideal place to do this. I suggest something like:

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'

# note that at this point, all models are required!

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

Or something of that nature. In your application, you require 'dmconfig' and have everything set up with that one require. DataMapper defers checking for the far end of relationships (say, projects in the Task model) until you call finalize or auto_upgrade!, so make sure all the models are required before you do this.

like image 199
namelessjon Avatar answered Jan 13 '23 10:01

namelessjon