I have the following minimal example DataMapper model:
# model.rb
require 'data_mapper'
class Job
include DataMapper::Resource
after :create, :create_id_based_data
property :id, Serial
property :magicNumber, String
def create_id_based_data
self.magicNumber = "#{self.id}_#{Random.rand()}"
self.save!
end
end
DataMapper.setup(:default, 'sqlite::memory:')
DataMapper.auto_migrate!
If I run the code in irb, "magicNumber" is not saved to the database:
irb -r ./model.rb
2.2.1 :001 > Job.all
=> []
2.2.1 :002 > Job.create
=> #<Job @id=1 @magicNumber="1_0.6245356525078689">
2.2.1 :003 > Job.all
=> [#<Job @id=1 @magicNumber=nil>]
My understanding is that DataMapper will prevent a repeated save
call inside of a save
callback, but shouldn't a save
call be allowable inside of a create
after hook? And even if a normal save
call is not allowed, shouldn't the save!
call bypass all callbacks and therefore be allowable?
Looking at this bug report, it appears the mechanism (run_once
) that prevents a loop of save
calls is still at play. Not clear if this is a bug or not. Using save_self
gives the behavior you want, at the cost of using a semi-public API.
# model.rb
require 'data_mapper'
class Job
include DataMapper::Resource
after :create, :create_id_based_data
property :id, Serial
property :magicNumber, String
def create_id_based_data
self.magicNumber = "#{self.id}_#{Random.rand()}"
save_self(false)
end
end
DataMapper.setup(:default, 'sqlite::memory:')
DataMapper.auto_migrate!
The result:
irb -r ./model.rb
2.1.0 :001 > Job.all
=> []
2.1.0 :002 > Job.create
=> #<Job @id=1 @magicNumber="1_0.7816860975338344">
2.1.0 :003 > Job.all
=> [#<Job @id=1 @magicNumber="1_0.7816860975338344">]
2.1.0 :004 >