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
Da开发者_开发百科taMapper.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?
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.
It looks like that might be caused by a typo in task.rb
belongs_to, :project
should be written as:
belongs_to :project
And for what it's worth, when using Sinatra, for example, I prefer to keep all of my models together in one lib/models.rb
file... at least for as long as that's manageable.
First of all, call DataMapper.finalize before you call auto_upgrade. Secondly, it's better to load the models, call finalize and then do DataMapper.auto_migrate! instead of calling auto_upgrade after each model definition.
精彩评论