Session Based Record Locking - Solutions?

All,

I’ve written a simple job/opportunity tracking database app via RoR.

I have about 10 internal users.

Sometimes 2 people will want to update the same record at more or less
the same time and they collide.

In particular user 1 may edit a record, then get distracted, and
finally an hour later they click save.

During that hour user 2 may have pulled up the record, edited it, and
saved it. The later save by user 1 undoes user 2’s changes.

I can’t think of any web technology that would help with this but …

I’m hoping that a session lock could somehow be used. Maybe a
background Java Script app or something could somehow keep a session
lock instantiated and if the browser is killed the seesion lock is
released?

Ideas welcome.

Thanks
Greg

Greg F.
The Norcross Group
Forensics for the 21st Century

Hi Greg,

In a similar situation I have simply used the ActiveRecord::Locking
module by adding a lock_version column to the table(s) in question and
handling the ActiveRecord::StaleObjectError if/when it is thrown. It’s
pretty simple really and will probalby be a lot easier to implment
than a global application mutex.

Anyway, HTH,
Dan.

Greg,

I don’t really have something to add having read Dan’s response –
looks like ActiveRecord already includes the approach I was going to
suggest. In case you weren’t aware of this kind of system,
essentially it involves keeping a timestamp with the record that is
updated everytime the record is. Then, when performing an update, the
system checks whether the timestamp on record matches the one that
the updater has – if not there’s been an update already and you’ll
need to handle it.

If you wanted to you could perhaps have something poll every 10
seconds or so (and on saving of course), then update where necessary.
Perhaps warn the user, update fields that haven’t changed, that kinda
thing.

Regards,
Paul

Greg,

I’ve only been using Ruby and Rails for a relatively short while, but
I believe what ActiveRecord does depends on how you call it’s methods.

I believe you’ll have to do something like

record = Record.find_by_id(1)
record.save!

Suffixing it with an exclamation mark should cause an error to be
raised should it fail.

Is that what you mean? Incidentally, it should be relatively trivial
to put together a unit test for this, probably a good way to go –
verify assumptions on how ActiveRecord deals with this stuff.

Regards,
Paul

On 2/23/06, Dan S. [email protected] wrote:

Hi Greg,

In a similar situation I have simply used the ActiveRecord::Locking
module by adding a lock_version column to the table(s) in question and
handling the ActiveRecord::StaleObjectError if/when it is thrown. It’s
pretty simple really and will probalby be a lot easier to implment
than a global application mutex.

Anyway, HTH,
Dan.

To get an failed update (with error message?) should I have to do
anything besides have a lock_version field? Should it work in devel
mode?

I ask because I already have a lock_version field in my table.

In my dev instance I just tried:

user 1: edit record, edit comment to say “Should Fail”
user 2: edit record, edit comment to say “Should Succeed”
user 2: click save, comment says “Should Succeed”
user 1: click save, comment says “Should Fail”

Obviously this is not what you described. For my 2 users I was using
a single client, but one was firefox and one was IE. I assume that
should qualify as seperate users.

Thanks
Greg

Ack, that’s probably because on the post of the User1 comment, the
model is being reloaded, so it gets the new lock version number which
it then happily increments. By default, this will only stop the case
when 2 people press save at the same instant and the following
happens:

  1. user1 loads modelA (lock version 0)
  2. user2 loads modelA (lock version 0)
  3. users 1&2 change data as they need to within their own models
  4. user1 saves modelA to table (incrementing lock version to 1)
  5. user2 saves modelA but lock version of model (0) does not match
    that in table (1) so exception is thrown.

A little but more work will be needed by the looks for you… Basically
you will need to get out the lock_version and pass it as a param to
your post, so that on the receiving action you can get the
lock_version from the DB before you update and compare to you posted
value, so you can fail fast on the action before you attempt to hit
the db.

Sorry bout that.

Dan

On 2/23/06, Paul I. [email protected] wrote:

Suffixing it with an exclamation mark should cause an error to be
raised should it fail.

Is that what you mean? Incidentally, it should be relatively trivial
to put together a unit test for this, probably a good way to go –
verify assumptions on how ActiveRecord deals with this stuff.

Regards,
Paul

Thanks Paul, but I’m still having problems.

My controller’s update method does not call save.

It is calling @record.update_attributes(params[:record]).

If I try to add an ! on the end I get a syntax error.

I don’t remember replaceing save with update_attributes, but maybe one
of my coworkers did that. Do you mind looking at your update method
and seeing what call it is using to update the record?

Thanks again
Greg

Greg F.
The Norcross Group
Forensics for the 21st Century

I think I’m done for the night. I’ll look into this tomorrow with fresh
eyes.

On 2/23/06, Dan S. [email protected] wrote:

  1. user2 saves modelA but lock version of model (0) does not match

Regards,

handling the ActiveRecord::StaleObjectError if/when it is thrown.

a single client, but one was firefox and one was IE. I assume that
Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails


Rails mailing list
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails


Greg F.
The Norcross Group
Forensics for the 21st Century