Ok, I am looking to implement something fairly straight forward in a Rails app I would say, but rails callbacks, transactions and caches are getting the better of me.
This is what I want to achieve:
Two objects project and task. Both have an attribute finish_date. Also a project :has_many => :tasks.
I want to tell the project that its own finish_date can never be earlier than the latest finish_date on its tasks. Whenever a task is updated, the project parent should check and adjust its own finish_date if required.
I have been messing with after_save callbacks and its not as simple as I imagined due to transactions and multiple versions of the same object in memory. Perhaps I am just doing it wrong.
How could I implement this in Rails?
How about the following
Taskmodel:The project’s
finish_datewill be set to the task’sfinish_date. The code is assuming, the currently saved tasked always has a laterfinished_dateas any other. It that’s a wrong assumption, just add the appropriateifstatement 🙂EDIT
My suggestion from the comment would be to have the
Taskas listed above and overwrite thefinish_datesetter inProjectlike so:Since I’m coding from my head, I’m not sure whether the project instance should be saved after this. Perhaps using
update_attributesin the setter might be a better idea.About the other solutions here
@Joelios solution suggested what I did, only not with overriding the setter. The problem with that is, that Rails included methods always use the setter (even
update_attributesandcreate). So with that, you had to call methodupdate_task_dateon your own which one might forget.@saverios solution suggests to use the Observer/Observable pattern. So, as I see it,
Projectwould become an observer of all itsTaskobjects. When aTaskchanges, it calls all its observers, i.e. its project, which itself updates itsfinish_date. It’s more of less the same what I suggested just with using a design pattern, hence making it more difficult.Another solution one could think about is to define a new function like
updateinProjectwhich iterates through all connected tasks, looking for the newestfinish_date. Thatupdatemethod would have to be called whenever a task updates. That would be really bad design because each update of one of n tasks would trigger n database queries and slow everything down.Hope that helps someone facing the same problem.