Forum: Ruby on Rails When to use optimistic locking?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Jason T. (Guest)
on 2006-05-09 20:26
(Received via mailing list)
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
Peter De Berdt (Guest)
on 2006-05-09 20:45
(Received via mailing list)
> 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
Jason T. (Guest)
on 2006-05-09 22:02
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
Jason T. (Guest)
on 2006-05-09 22:18
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
Kevin O. (Guest)
on 2006-05-09 22:34
(Received via mailing list)
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
Jeremy K. (Guest)
on 2006-05-09 22:43
(Received via mailing list)
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?  :)

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
Jason T. (Guest)
on 2006-05-09 22:56
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
Jason T. (Guest)
on 2006-05-09 23:22
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?  :)
>
> 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
This topic is locked and can not be replied to.