Hello, What I really wanted I now believe has to be done and provided by the native DB or implemented via some plumbing connection between rails and the db (which I don't think is provided by any vendors…).
Something akin to a subscriber/publisher design pattern, where I can subscribe to the DB from rails and say, "Notify me when anything to do with this row" has changed.. and then when something does change the DB is the one that communicates back through the db connection signalling to call .reload… Like I don't understand why this is not a standard in any ORM implementation… surely it's never a good situation to be dealing with stale objects at any time That's what I expect from an ORM I guess which probably doesn't exist. To me the idea of encapsulating a complete DB row as an object is meaningless if the underlying data can change at any time, and I can't tell until I try to save it. Like once I create that ActiveRecord object.. it's stale. So all calculations that I perform on those attributes of that object could well and truly be meaningless. Wouldn't it be great if rails automatically knew that the underlying db actually has changed either via an attribute on the AR model (e.g. model.attribute_db_value_changed?), and or a config setting that allows you to always work with updated db values in real time if you choose to, all without polling the DB, but Rails being informed by exception. The current situation which I am now in is to always assume that I am the only one in the world, and that everything is ok, until I try to save, and then only then do I realise my object I have been dealing with is stale, so go back, reload, and re-work out everything again (doing any necessary merges of state) that you were trying to do with the updated object, and then try to save again (with the possibility of just doing it all over again if someone trumps you again). I would rather have it so that I am midway calculating the state of an object, and realise halfway that the underlying model has changed, so even before I attempt to save it I can rectify my calculations on the fly. I'm assuming that when you say row locking thats pessimistic locking? Which is the other alternative which I will give a go as well, although I think on initial inspection has the possibility of deadlocking this particular scenario.. But the other thing that I understand is that you can't have a read lock (where you block a select statement from even coming back with values because someone else is updating it), only a read lock on "select for update" scenarios… So that's actually my problem - I read a value and depend on that value, and so during the time of me calculating things with that value if it has changed, I need to know, but I can't until I have done my calculations, and find that value has changed when I try to save - but some instances, you don't even need to save.. you just do the calculation and pass that along.. which by that stage is incorrect. I think everyone is right in that I think the best way is to re-think really what it is I am trying to do…perhaps I have just fell in love with Rails automagically doing everything for me that my expectations are now beyond reasonable :) Cheers -Chris On Fri, Nov 19, 2010 at 8:47 AM, Korny Sietsma <[email protected]> wrote: > You should still think carefully about what it is you are trying to do. > If you just catch the optimistic locking exception, and automatically > reload and save, then you are ensuring the second user's change overwrites > the first. The second user will never see the first user's change. That's > not really optimistic locking at all. Even if you merge the two sets of > changes, merging is tricky in all but the most trivial of cases. > > More usually, optimistic locking involves *informing* the second user : > "Another user has changed this record - please review their changes and try > again" - this guarantees that you won't get merge collisions or other > surprises. > > Be warned - much pain and trauma has been experienced in the past by people > trying to automatically manage simultaneous changes in an automated way. > The best answer is usually to say "why do you really want to do this?" > > - Korny > > On Thu, Nov 18, 2010 at 6:29 PM, Chris Mayan <[email protected]>wrote: > >> SOLVED! >> >> Thanks Mikel for sending me in the right direction - I ended up finding a >> pure rails way of doing it... (i'm switching search engines I think). >> >> The solution for anyone else interested is "Optimistic Locking" which by >> default gets turned on on any models with a column that contains an integer >> column called "lock_version" (which you initialise to 0 and leave alone >> thereafter as AR will manage it then). >> >> Then when 2 different processes tries to update the table it will check >> the lock version sequence number and it will realise it is working with a >> stale version (as another process has updated it) and thus will throw an >> exception (ActiveRecord::StaleObjectError), where then you can call >> .reload(), before you try to save again, more effeciently. >> >> Brilliant... thanks :) >> >> Cheers >> Chris >> >> >> On Thu, Nov 18, 2010 at 6:05 PM, Mikel Lindsaar <[email protected]>wrote: >> >>> On 18/11/2010, at 5:47 PM, Chris Mayan wrote: >>> > Question: How on earth do you make Active Record model objects be multi >>> thread / multi process safe, so that when an attribute is changed in one >>> process (such as from a delayed job) whilst another process (such as a user >>> / web server process which has loaded / mapped the same db row in question >>> as an AR model object), access the attribute, will automatically uses the >>> new modified attribute value... _without_ having to call model.reload >>> manually? >>> >>> You can't... well... you can... but you have to call reload somewhere. >>> >>> The way this is handled best is using record locking in conjunction with >>> database transactions which provides access to row and table locking. >>> >>> Then while you are doing the update, check to make sure that the record >>> has not already been updated before performing your action, all within a >>> transaction. >>> >>> Hope that nudges you in the right direction. >>> >>> >>> Mikel Lindsaar >>> http://rubyx.com/ >>> http://lindsaar.net/ >>> >>> >>> >>> >>> -- >>> You received this message because you are subscribed to the Google Groups >>> "Ruby or Rails Oceania" group. >>> To post to this group, send email to [email protected]. >>> To unsubscribe from this group, send email to >>> [email protected]<rails-oceania%[email protected]> >>> . >>> For more options, visit this group at >>> http://groups.google.com/group/rails-oceania?hl=en. >>> >>> >> -- >> You received this message because you are subscribed to the Google Groups >> "Ruby or Rails Oceania" group. >> To post to this group, send email to [email protected]. >> To unsubscribe from this group, send email to >> [email protected]<rails-oceania%[email protected]> >> . >> For more options, visit this group at >> http://groups.google.com/group/rails-oceania?hl=en. >> > > > > -- > Kornelis Sietsma korny at my surname dot com http://korny.info > "Every jumbled pile of person has a thinking part > that wonders what the part that isn't thinking > isn't thinking of" > > -- > You received this message because you are subscribed to the Google Groups > "Ruby or Rails Oceania" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]<rails-oceania%[email protected]> > . > For more options, visit this group at > http://groups.google.com/group/rails-oceania?hl=en. > -- You received this message because you are subscribed to the Google Groups "Ruby or Rails Oceania" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/rails-oceania?hl=en.
