When to use optimistic locking?


#1

Hi All,

I’m having some trouble deciding when and how to implement optimistic
locking.

Let’s say I have a multiuser Rails app, and let’s say it stores,
among other things “vital” customer information.

The standard methods created by the Rails generate scaffold script
look like this:

def edit
@customer = Customer.find(params[:id])
end

def update
@customer = Customer.find(params[:id])
if @customer.update_attributes(params[:customer])
flash[:notice] = ‘Customer was successfully updated.’
redirect_to :action => ‘show’, :id => @customer
else
render :action => ‘edit’
end
end

What if I want to guard against 2 people simultaneously updating the
same customer record? How would I go about doing this? I can’t find
any examples online, and I’m a bit lost.

Thanks,

: )

Jason


#2

What if I want to guard against 2 people simultaneously updating
the same customer record? How would I go about doing this? I can’t
find any examples online, and I’m a bit lost.

Well, first of all, you need a lock_version column in your model
(table) (or override it with the “set_locking_column” method). If a
record has been changed by someone else, Rails will throw a
StaleObjectError, you need to trap this error and handle it
appropriately (present the user with a dialog confirming to update
the record anyway or cancel it). It’s up to you to find a way to
handle the error.

Best regards

Peter De Berdt


#3

Peter De Berdt wrote:

What if I want to guard against 2 people simultaneously updating
the same customer record? How would I go about doing this? I can’t
find any examples online, and I’m a bit lost.

Well, first of all, you need a lock_version column in your model
(table) (or override it with the “set_locking_column” method). If a
record has been changed by someone else, Rails will throw a
StaleObjectError, you need to trap this error and handle it
appropriately (present the user with a dialog confirming to update
the record anyway or cancel it). It’s up to you to find a way to
handle the error.

Best regards

Peter De Berdt

Thanks Peter, but in the scaffold generated CRUD code, the model state
is lost between the “edit” and “update” calls. – the StaleObjectError
will never be thrown.

: )

Jason


#4

Jason T. wrote:

Hi All,

I’m having some trouble deciding when and how to implement optimistic
locking.

Let’s say I have a multiuser Rails app, and let’s say it stores,
among other things “vital” customer information.

The standard methods created by the Rails generate scaffold script
look like this:

def edit
@customer = Customer.find(params[:id])
end

def update
@customer = Customer.find(params[:id])
if @customer.update_attributes(params[:customer])
flash[:notice] = ‘Customer was successfully updated.’
redirect_to :action => ‘show’, :id => @customer
else
render :action => ‘edit’
end
end

What if I want to guard against 2 people simultaneously updating the
same customer record? How would I go about doing this? I can’t find
any examples online, and I’m a bit lost.

Thanks,

: )

Jason

The more I think about it, there doesn’t seem to be a way to take
advantage of Active Record’s optimistic locking when using the standard
scaffold generated CRUD approach because the model state is lost between
the call to “edit” and the subsequent call to “update”. – The
ActiveRecord::StaleObjectError will never be thrown.

Do you have to manually track the value of the lock_version column?

There must be a more elegant solution.

I must be missing something. I just can’t figure out what.

  • Jason

#5

On May 9, 2006, at 11:18 AM, Jason T. wrote:

The more I think about it, there doesn’t seem to be a way to take
advantage of Active Record’s optimistic locking when using the
standard
scaffold generated CRUD approach because the model state is lost
between
the call to “edit” and the subsequent call to “update”. – The
ActiveRecord::StaleObjectError will never be thrown.

Do you have to manually track the value of the lock_version column?

Yes.

There must be a more elegant solution.

Wrap up the lock_version handling by passing it in session, crypted
form param, or similar.

I must be missing something. I just can’t figure out what.

A well-tested patch? :slight_smile:

Michael S. did quite a bit of work on an alternate scaffolding
toolset that includes conflict resolution. See his Boilerplate lib:
http://www.schuerig.de/michael/boilerplate/

Best,
jeremy


#6

Kevin O. wrote:

On Tuesday, May 09, 2006, at 8:18 PM, Jason T. wrote:

look like this:
else
: )

removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails

It works. I think it puts a hidden text field with the value of the
lock_version in the form. When you go to save it, it compares the value
to the one in the database. If the one in the database is different,
then someone has modified the record. Once saved, the value is
incremented.

So the state of the record is retained. I think AR is smart enough to
know what to do with this without adding additional code, which is why
they call it a ‘magic’ column.

_Kevin

Hi Kevin,

I just double checked. – There doesn’t seem to bee any hidden field.

  • Jason

#7

On Tuesday, May 09, 2006, at 8:18 PM, Jason T. wrote:

look like this:
else
: )

removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails

It works. I think it puts a hidden text field with the value of the
lock_version in the form. When you go to save it, it compares the value
to the one in the database. If the one in the database is different,
then someone has modified the record. Once saved, the value is
incremented.

So the state of the record is retained. I think AR is smart enough to
know what to do with this without adding additional code, which is why
they call it a ‘magic’ column.

_Kevin


#8

Jeremy K. wrote:

On May 9, 2006, at 11:18 AM, Jason T. wrote:

The more I think about it, there doesn’t seem to be a way to take
advantage of Active Record’s optimistic locking when using the
standard
scaffold generated CRUD approach because the model state is lost
between
the call to “edit” and the subsequent call to “update”. – The
ActiveRecord::StaleObjectError will never be thrown.

Do you have to manually track the value of the lock_version column?

Yes.

There must be a more elegant solution.

Wrap up the lock_version handling by passing it in session, crypted
form param, or similar.

I must be missing something. I just can’t figure out what.

A well-tested patch? :slight_smile:

Michael S. did quite a bit of work on an alternate scaffolding
toolset that includes conflict resolution. See his Boilerplate lib:
http://www.schuerig.de/michael/boilerplate/

Best,
jeremy

Thanks Jeremy. – I’m off to check out Boilerplate lib right now.

  • Jason