[DataMapper] Marking attributes as dirty

221 views
Skip to first unread message

Aaron Pfeifer

unread,
Apr 20, 2010, 9:28:31 PM4/20/10
to DataMapper
Hey guys,

One of the things I've noticed with DataMapper's dirty attribute
tracking is that there doesn't seem to be an elegant way to mark
attributes as dirty when they're modified in-place. For example, you
might have the following:

p = Person.get(1)
p.name << "foo"
p.dirty? # => false

Ideally, there would be a way to mark an attribute as dirty (like
ActiveRecord's {attribute}_will_change!). Right now, the way to
manually do this is pretty brittle from release to release.

Is this a feature that's been considered before or is it open to
consideration? For what it's worth, the reason I'm looking for this
functionality is that I need it to properly save DataMapper records in
state_machine when a loopback occurs. I'd like to have a more stable
implementation for that scenario (rather than messing with things in
DataMapper that are likely intended to be for internal usage only).

Thanks.

--
You received this message because you are subscribed to the Google Groups "DataMapper" group.
To post to this group, send email to datam...@googlegroups.com.
To unsubscribe from this group, send email to datamapper+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/datamapper?hl=en.

Ted Han

unread,
Apr 20, 2010, 10:08:36 PM4/20/10
to datam...@googlegroups.com
Hey Aaron,

This is totally open to suggestions, this is actually something i discussed w/ dkubb last week, although my problem was only loosely related:


02:16 <@dkubb> knowtheory: one of the things I'd like to do is change how retrieved data is mapped to the resources
02:16 <@dkubb> knowtheory: for example, right now we map each "Hash" to the resource immediately
02:16 < knowtheory> o?
02:16 <@dkubb> knowtheory: what I would like to do is store this Hash somewhere, but not assign it.  when the attribute is asked for, I'd take the value, dup it, and assign that to the resource
02:17 < knowtheory> yep!
02:17 <@dkubb> knowtheory: what this would do is two things, fix the problem you noticed, but more importantly provide a simple way to do dirtyness checking
02:17 <@dkubb> knowtheory: actually this is something I've wanted to do for a few months now, your problem is just more evidence that it's the correct path
02:18 <@dkubb> knowtheory: a nice side effect of this is that since we're deferring assignment of the values, retrieving objects from the datastore should actually increase in speed
02:18 < knowtheory> Yep :)
02:19 < knowtheory> So, where should the attrs be stored? :D
02:19 <@dkubb> knowtheory: plus there's a good chance that you won't use all of the values anyway, so by deferring, we save time if we never have to do the work
02:19 <@dkubb> I dunno :P
02:20 <@dkubb> when using the ActiveRecord pattern it's ok to store the objects somewhere inside the object as long as you make sure there's a low chance of collision in the method name
02:20 <@dkubb> but I'm more worried about how we'd do it when mapping normal ruby objects in the future
02:21 < knowtheory> yeah.
02:21 <@dkubb> I think in those cases, since you'd probably fetch using some kind of Session/UoW object, it would store the mapping
02:21 < knowtheory> dkubb: neat.  yeah i was going to ask whether there was some sort of global registry of that info...
02:22 < knowtheory> which doesn't seem quite natural to me in terms of what data lives where...
02:22 < knowtheory> but the identity map is basically the same sort of object
02:22 <@dkubb> even with the DataMapper pattern, I think we have to wrap the accessor/mutators in normal objects anyway, so those could hold a reference to the UoW that was used to fetch the object

Clifford Heath

unread,
Apr 20, 2010, 10:20:28 PM4/20/10
to datam...@googlegroups.com
In ActiveFacts, the accessor for an attribute returns a proxy.
Using delegation, they're almost(*) completely invisible, except
for a single added method, #naked, which returns the unproxied
value.

Assignment to a proxy goes through a bunch of code relevant to
ActiveFacts, and which will have all required dirty marking (not yet).

Anyhow, it's one implementation possibility.

(*) Differences occur when you go SomeClass === thing.attr
because === doesn't use the #class, instead accessing the actual
class object from the C code level (so a delegate can't duck-type
the #class method). However, I simply avoid === and use
thing.attr.is_a?(SomeClass) instead.

Clifford Heath, Data Constellation, http://dataconstellation.com
Agile Information Management and Design.

Aaron Pfeifer

unread,
Aug 10, 2011, 9:00:21 AM8/10/11
to datam...@googlegroups.com
Hey everyone -

I apologize for re-opening a year-old thread, but I wanted to check in again to see if this feature had been considered by anyone else or whether there were any plans to address it.  The implementation I had been using to mark an attribute as dirty will be broken (with deprecation notices) again once the next version of DM is released.

Currently, the only way to achieve this is by something like the following:

  object.persisted_state = DataMapper::Resource::State::Dirty.new(self) if persisted_state.is_a?(DataMapper::Resource::State::Clean)
  property = self.class.properties['name']
  object.persisted_state.original_attributes[property] = name unless persisted_state.original_attributes.include?(property)

Obviously this isn't ideal and, as mentioned in the original post, pretty brittle.  If there's agreement on how you would want to handle this situation in DM, I could certainly look into getting someone to work on it.  Just for reference, I'm encountering this in my state_machine library and looking into how to really address the latest pull request -- https://github.com/pluginaweek/state_machine/pull/106.

Thanks for any thoughts!
Reply all
Reply to author
Forward
0 new messages