This project is archived and is in readonly mode.
Dirty Attributes with Associations
-
Pratik
- Assigned user set to Jeremy Kemper
I think this is a better fit for a plugin. It's not very common to track association changes.
-
TheBreeze
- Tag changed from activerecord, enhancement, patch, tested to association, changes
- Assigned user cleared.
Josh: I wrote plugin for this functionality. The plugin definitely needs some work, including specs, but it works well. I'll be presenting it at SDRuby this Thursday, so I'm looking to get some work done on it this week. Info below:
http://github.com/TheBreeze/shad...
Contact me if you're interested.
-
ronin-24025 (at lighthouseapp)
Re: "It's not very common to track association changes."
I would say that the data suggests otherwise.
And as an example: "→ Assigned user changed from “” to “Jeremy Kemper”".
I agree with Josh, we definitely need this in.
And Dirty needs a whole lot of work. Where it could have been an elegant and conceptually simple solution, it's currently certainly not. This is giving rise to cruft (will_change!), unreliability and a whole load of recent tickets.
I've seen votes for better syntax too: person.name.changed? instead of person.name_changed? since person.name.changed? asks the attribute (instead of the model) if it has changed, which is more semantically correct, and represents a more meta-data purpose. Plus it's far less painful to type.
-
Josh Susser
person.name.changed? instead of person.name_changed?
This seems like a bad idea to me. How can you tell the difference between asking if person's name attribute has a different value and the name itself having an attribute value changed? This could easily happen if
nameis an association to a model that contains first, middle and last attributes. Also, the API you propose would require layering a proxy object on top of simple attribute access the way it is on associations now. Sounds very complicated for minimal short-term benefit. Adding an AttributeProxy object could do some interesting stuff, but it would be a huge change and seems like a 3.0 kind of move. -
Jeremy Kemper
- State changed from new to incomplete
- Assigned user set to Jeremy Kemper
Joran, your elegant, simple patches are welcome ;)
Josh, it feels wrong to add association awareness to a feature that deals only with attribute changes. Perhaps it's asking for a better abstraction.
-
ronin-24025 (at lighthouseapp)
Jeremy, thanks, I better keep my mouth shut more in future! ;)
Josh, surely "the difference between asking if person's name attribute has a different value and the name itself having an attribute value changed" is already the case with the existing syntax? Turtles all the way down? I agree it's complicated. And it's not the most important issue. In this case, it's getting rid of will_change! and adding better association support (I had to redefine other_ids=() today because of this and it's no fun).
On the subject of a simpler design, hinging attribute_changed? on the attribute setter requires the will_change! flag and discourages use of methods such as attribute.upcase! etc. It's a slippery slope trying to remember when and where to use will_change!. The one advantage however is that the row is not kept in memory twice. i.e. there's no "before" and "after". But this is a machine advantage with not much human upside.
I think the memory cost of a before and after approach is worth it. Then attributes can be changed any which way. There's no need for will_change! and Dirty gets more simple and reliable, esp. re: partial updates.
More joy for the human. More pain for the machine.
I'll put my newbie Rails simple mind to it and see what I can do. ;)
-
Josh Susser
Too many Joshes! Plz use an unambiguous name when there's more than one of us about. How ironic when the point I'm trying to make is about ambiguous naming, heh.
surely "the difference between asking if person's name attribute has a different value and the name itself having an attribute value changed" is already the case with the existing syntax?
Not really. Right now name.changed? will tell you if a Name model has any changed attributes. It's difficult to tell by looking at the code if person.name.changed? means the person has a new name or the same name with a different attribute.
Whenever you introduce a proxy you need to make sure it doesn't block methods on its target. For an example, create a Missile model with a :target attribute. Silo.belongs_to :missile. silo.missile.target returns.... the silo's missile, not the missile's target.
Sorry if this is off-topic. I'm all for improving the dirty tracking API. Just let's not make things worse.
-
ronin-24025 (at lighthouseapp)
Josh Susser, right, got you now.
-
cs
Currently, to track dirty attributes on associations, you need to reference with a foreign key.
How to do that with habtm associations?
Thx, cs.
-
yves.vogl (at dock42)
I just ran into the same problem.
There's a Project model which has_and_belongs_to_many :users After assigning adding some more users and removing a few from the team (project.user_ids) I'd like to write an observer which determines the new teammates by substraction of project.users and project.users_were On the one hand I understand that especially a habtm association is more likely a foreign mapping of associations than a attribute of an object itself – on the other hand one could argue from a more abstract and object-related point of view where an association is just a way composing a single object.
Using something like acts_as_versioned for this scenario seems to me like breaking a butterfly on the wheel. So… what do you suggest?
-
Josh Pencheon
I've also had a go at making a plugin to do this, very much pre-alpha, but if you want a look:
github.com/joshpencheon/dirty_associations
-
Leandro Pedroni
Well, it would make sense that if you overwrite the content of an object's association you would be able to know that you did so and what you are replacing.
user = User.last user.ticket # => #<Ticket id:101, queue_position:41, ...> user.create_ticket # => #<Ticket id:102, queue_position:42, ...> user.ticket_changed? # => true user.ticket_was # => #<Ticket id:101, queue_position:41, ...>All I can think of now is changing the association_accessor_methods, association_constructor_method and collection_accessor_methods in Activerecord::Associations and cache the old object in the reflection itself. But I'm not sure I understood any of that correctly and that wouldn't be as modular as Dirty that simply wraps around write_attribute when loaded.
-
Brian Armstrong
+1 for this - I think it makes sense to include.
Rationale: when I think of objects in real life "changing" I don't distinguish attributes vs associations. This is closest to it's meaning in the English language. For example, if I say "there is something different about this class" I could just as easily be referring to the new teacher/students in the class (associations) as the title of the class (attribute).
It also feels more "rubyish" following the principles of:
1. emphasize human, rather than computer, needs and
2. the principle of least astonishment (POLA), meaning that the language should behave in such a way as to minimize confusionBasically - when I heard about the dirty functions, it was my first assumption to assume/hope this encompassed associations, since that seemed most natural. But I wasn't really surprised to find they didn't, given that it's obviously harder to implement.
Anyway, just wanted to add that...
-
Santiago Pastorino
- State changed from incomplete to open
- Importance changed from to
This issue has been automatically marked as stale because it has not been commented on for at least three months.
The resources of the Rails core team are limited, and so we are asking for your help. If you can still reproduce this error on the 3-0-stable branch or on master, please reply with all of the information you have about it and add "[state:open]" to your comment. This will reopen the ticket for review. Likewise, if you feel that this is a very important feature for Rails to include, please reply with your explanation so we can consider it.
Thank you for all your contributions, and we hope you will understand this step to focus our efforts where they are most helpful.
-
Santiago Pastorino
- State changed from open to stale
