
Save fails for a less-than-obvious reason involving Time representations
Reported by Greg Campbell | October 27th, 2009 @ 12:50 PM | in 0.10.2
The underlying problem is that DataMapper considers a particular property to have changed, but the storage engine (MySQL in this case) does not, due to differences in precision (Ruby Time objects include microseconds, MySQL TIMESTAMP and DATETIME columns do not). When a resource attempts to save, it first saves its parents, which fails here because MySQL returns that zero rows changed.
This caused a bunch of specs to break for me when updating my application for DM 0.10 (and took quite a while to track down using a debugger), and I'm not sure if it's intended behavior or not. For now, I've worked around it at an application level (comparing to_i representations of timestamps before setting them), but it would be nice if DM could at least provide some indication of why the save failed. I'm calling this a "regression" for now because it worked as I would expect it to in 0.9.x, but feel free to remove the tag if this is the intended behavior. Example follows:
require 'rubygems'
require 'dm-core'
DataMapper.setup(:default, 'mysql://localhost/save_failure')
class SecretPlan
include DataMapper::Resource
property :id, Serial
property :name, String
property :steps_changed_at, Time
has n, :steps
end
class Step
include DataMapper::Resource
property :id, Serial
belongs_to :secret_plan
property :description, String
end
DataMapper.auto_migrate!
plan = SecretPlan.create(:name => "underpants", :steps_changed_at => Time.now)
step = plan.steps.create(:description => "Steal underpants")
step.description = "???"
# The next line causes the problem. steps_changed_at will be considered to be "dirty" by DM,
# as the Ruby Time object includes microseconds. However, persisting to MySQL (and perhaps other
# storage engines?) will return that zero rows changed, because mysql dates/times only store
# precision down to the second, so it treats the value as unchanged. This then prevents the
# step from saving, as the parent did not save successfully.
plan.steps_changed_at = Time.now
puts step.save #false
puts step.reload.description # "Steal underpants"
Comments and changes to this ticket
-
Dan Kubb (dkubb) October 27th, 2009 @ 10:59 PM
- State changed from new to unconfirmed
Greg, can you try this with edge dm-core?
I changed it so Resource#update is idempotent, so repeated attempts to save the record always return true.
-
-
Dan Kubb (dkubb) November 6th, 2009 @ 01:42 AM
- State changed from unconfirmed to resolved
- Milestone set to 0.10.2
Please Sign in or create a free account to add a new ticket.
With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »