# record locking

**URL:** <https://discuss.rubyonrails.org/t/record-locking/28331>\
**Category:** rubyonrails-talk\
**Created:** [April 21, 2008, 5:43pm UTC](https://discuss.rubyonrails.org/t/record-locking/28331 "2008-04-21T17:43:08Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![Craig\_White1](https://avatars.discourse-cdn.com/v4/letter/c/3ec8ea/32.png) [@Craig\_White1](https://discuss.rubyonrails.org/u/Craig_White1)\
**Post date:** [April 21, 2008, 5:43pm UTC](https://discuss.rubyonrails.org/t/record-locking/28331/1 "2008-04-21T17:43:08Z")

</div>

Looking through the api on record locking I'm confused.

given the stateless nature of html, it's entirely possible that someone might click on 'edit' and then simply abandon their 'edit' functions without ever saving - which tells me that I should just have a column in each table called 'lock\_version' with a default of 0 - (Opportunistic locking) right?

Then I need a method in each model employing record locking to rescue any exceptions raised by multiple people trying to edit without saving and in essence checking out the data again and discarding their edits.

Do I have this right?

Craig

---

<div class="post-metadata">

**Author:** ![Steve\_Ross](https://avatars.discourse-cdn.com/v4/letter/s/3d9bf3/32.png) [@Steve\_Ross](https://discuss.rubyonrails.org/u/Steve_Ross)\
**Post date:** [April 21, 2008, 6:08pm UTC](https://discuss.rubyonrails.org/t/record-locking/28331/2 "2008-04-21T18:08:11Z")

</div>

Yes, you are right. It is dangerous to leave a record locked any longer than necessary, and very dangerous to leave it locked if you don't absolutely know the transaction will complete. If you want optimistic locking, add a column called lock\_version. If you want pessimistic locking, see this:

[http://ryandaigle.com/articles/2006/6/27/whats-new-in-edge-rails-pessimistic-locking](http://ryandaigle.com/articles/2006/6/27/whats-new-in-edge-rails-pessimistic-locking)

It's safe to use optimistic locking across http requests if you don't mind failed updates when collisions occur. Otherwise, consider pessimistic, as described.

G'luck!

---

<div class="post-metadata">

**Author:** ![Craig\_White1](https://avatars.discourse-cdn.com/v4/letter/c/3ec8ea/32.png) [@Craig\_White1](https://discuss.rubyonrails.org/u/Craig_White1)\
**Post date:** [April 21, 2008, 7:01pm UTC](https://discuss.rubyonrails.org/t/record-locking/28331/3 "2008-04-21T19:01:56Z")

</div>

> \> \> Looking through the api on record locking I'm confused. \> \> given the stateless nature of html, it's entirely possible that  
> \> someone \> might click on 'edit' and then simply abandon their 'edit' functions \> without ever saving - which tells me that I should just have a  
> \> column in \> each table called 'lock\_version' with a default of 0 - (Opportunistic \> locking) right? \> \> Then I need a method in each model employing record locking to rescue \> any exceptions raised by multiple people trying to edit without saving \> and in essence checking out the data again and discarding their edits. \> \> Do I have this right? \> \> Craig
> 
> Yes, you are right. It is dangerous to leave a record locked any  
> longer than necessary, and very dangerous to leave it locked if you  
> don't absolutely know the transaction will complete. If you want  
> optimistic locking, add a column called lock\_version. If you want  
> pessimistic locking, see this:
> 
> [http://ryandaigle.com/articles/2006/6/27/whats-new-in-edge-rails-pessimistic-locking](http://ryandaigle.com/articles/2006/6/27/whats-new-in-edge-rails-pessimistic-locking)
> 
> It's safe to use optimistic locking across http requests if you don't  
> mind failed updates when collisions occur. Otherwise, consider  
> pessimistic, as described.

---

<div class="post-metadata">

**Author:** ![Craig\_White1](https://avatars.discourse-cdn.com/v4/letter/c/3ec8ea/32.png) [@Craig\_White1](https://discuss.rubyonrails.org/u/Craig_White1)\
**Post date:** [April 21, 2008, 10:42pm UTC](https://discuss.rubyonrails.org/t/record-locking/28331/4 "2008-04-21T22:42:01Z")

</div>

> Looking through the api on record locking I'm confused.
> 
> given the stateless nature of html, it's entirely possible that someone might click on 'edit' and then simply abandon their 'edit' functions without ever saving - which tells me that I should just have a column in each table called 'lock\_version' with a default of 0 - (Opportunistic locking) right?
> 
> Then I need a method in each model employing record locking to rescue any exceptions raised by multiple people trying to edit without saving and in essence checking out the data again and discarding their edits.

---

<div class="post-metadata">

**Author:** ![Craig\_White1](https://avatars.discourse-cdn.com/v4/letter/c/3ec8ea/32.png) [@Craig\_White1](https://discuss.rubyonrails.org/u/Craig_White1)\
**Post date:** [April 21, 2008, 10:53pm UTC](https://discuss.rubyonrails.org/t/record-locking/28331/5 "2008-04-21T22:53:57Z")

</div>

> \> Looking through the api on record locking I'm confused. \> \> given the stateless nature of html, it's entirely possible that someone \> might click on 'edit' and then simply abandon their 'edit' functions \> without ever saving - which tells me that I should just have a column in \> each table called 'lock\_version' with a default of 0 - (Opportunistic \> locking) right? \> \> Then I need a method in each model employing record locking to rescue \> any exceptions raised by multiple people trying to edit without saving \> and in essence checking out the data again and discarding their edits. ---- OK - something must be wrong with my controller code then.
> 
> I added 'lock\_version' to my 'clients' table and restarted my mongrels.
> 
> in script/console, opportunistic locking works as advertised in the API
> 
> but using 2 separate browsers (1 Firefox, 1 Konqueror) with 2 separate sessions, I can update either in any order without an issue and the updates are saved and the 'lock\_version' value simply increments.
> 
> this is my controller code...can you see how I might be defeating opportunistic locking?
> 
> &nbsp;&nbsp;id = params[:id] &nbsp;&nbsp;if id && @client.valid? &nbsp;&nbsp;&nbsp;&nbsp;begin &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@client.update\_attributes(params[:client]) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flash[:notice] = 'Client was successfully updated.' &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redirect\_to :back &nbsp;&nbsp;&nbsp;&nbsp;rescue &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;flash[:notice] = "Client record was changed by someone else \ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while you were editing and you will have to edit again, \ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;starting over" &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redirect\_to :back &nbsp;&nbsp;&nbsp;&nbsp;end &nbsp;&nbsp;else &nbsp;&nbsp;&nbsp;&nbsp;flash[:notice] = "Danger Will Robinson" &nbsp;&nbsp;&nbsp;&nbsp;redirect\_to :back &nbsp;&nbsp;end

---

<div class="post-metadata">

**Author:** ![Frederick\_Cheung](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/frederick_cheung/32/3901_2.png) [@Frederick\_Cheung](https://discuss.rubyonrails.org/u/Frederick_Cheung)\
**Post date:** [April 21, 2008, 11:11pm UTC](https://discuss.rubyonrails.org/t/record-locking/28331/6 "2008-04-21T23:11:03Z")

</div>

> OK - something must be wrong with my controller code then.
> 
> I added 'lock\_version' to my 'clients' table and restarted my  
> mongrels.
> 
> in script/console, opportunistic locking works as advertised in the  
> API
> 
> but using 2 separate browsers (1 Firefox, 1 Konqueror) with 2 separate sessions, I can update either in any order without an issue and the updates are saved and the 'lock\_version' value simply increments.

This is intended. Opportunistic locking guards you from changes  
happening behind your back in between you doing foo = Foo.find(123)  
and foo.save Pessimistic locking has a similar sort of the database transaction  
it's enclosed in, and you wouldn't want that lasting beyond a single  
request (apart from anything else, if you have more than 1 mongrel,  
there's no guarantee you won't get some requests served by 1 mongrel  
and one by the other).

It sounds as though you're worried about the record changing in  
between the user viewing the form and you saving the record. There's  
no support for that builtin, but I think you could extend the  
principle of optimistic locking (include the current lock\_version as a  
hidden field on the form)

Fred

---

<div class="post-metadata">

**Author:** ![Craig\_White1](https://avatars.discourse-cdn.com/v4/letter/c/3ec8ea/32.png) [@Craig\_White1](https://discuss.rubyonrails.org/u/Craig_White1)\
**Post date:** [April 21, 2008, 11:35pm UTC](https://discuss.rubyonrails.org/t/record-locking/28331/7 "2008-04-21T23:35:39Z")

</div>

> It sounds as though you're worried about the record changing in  
> between the user viewing the form and you saving the record. There's  
> no support for that builtin, but I think you could extend the  
> principle of optimistic locking (include the current lock\_version as a  
> hidden field on the form)

---

<div class="post-metadata">

**Author:** ![Craig\_White1](https://avatars.discourse-cdn.com/v4/letter/c/3ec8ea/32.png) [@Craig\_White1](https://discuss.rubyonrails.org/u/Craig_White1)\
**Post date:** [April 21, 2008, 11:50pm UTC](https://discuss.rubyonrails.org/t/record-locking/28331/8 "2008-04-21T23:50:29Z")

</div>

> \> It sounds as though you're worried about the record changing in  
> \> between the user viewing the form and you saving the record. There's  
> \> no support for that builtin, but I think you could extend the  
> \> principle of optimistic locking (include the current lock\_version as a  
> \> hidden field on the form) \> ---- yeah - I sort of figured that out (the hidden field on the form sending back the lock\_version value that it checked out) but this causes me a problem with validations now.
> 
> Here's the issue in simplistic form...
> 
> controller code...
> 
> before optimistic locking
> 
> if @client.update\_attributes(params[:client]) &nbsp;&nbsp;flash[:notice] = "Bravo" &nbsp;&nbsp;redirect\_to :back else &nbsp;&nbsp;flash[:notice] = @client.validate &nbsp;&nbsp;redirect\_to :back end
> 
> NOW, with opportunistic locking...
> 
> if whatever &nbsp;&nbsp;begin &nbsp;&nbsp;&nbsp;&nbsp;@client.update\_attributes(params[:client]) &nbsp;&nbsp;&nbsp;&nbsp;flash[:notice] = "Bravo" &nbsp;&nbsp;&nbsp;&nbsp;redirect\_to :back &nbsp;&nbsp;rescue &nbsp;&nbsp;&nbsp;&nbsp;flash[:notice] = "Something changed in the interim" &nbsp;&nbsp;&nbsp;&nbsp;redirect\_to :back &nbsp;&nbsp;end end
> 
> The validate is lost in the rescue...how do I get my cake too?

---

<div class="post-metadata">

**Author:** ![Jodi1](https://avatars.discourse-cdn.com/v4/letter/j/bb73d2/32.png) [@Jodi1](https://discuss.rubyonrails.org/u/Jodi1)\
**Post date:** [April 21, 2008, 11:53pm UTC](https://discuss.rubyonrails.org/t/record-locking/28331/9 "2008-04-21T23:53:31Z")

</div>

Craig -

---

<div class="post-metadata">

**Author:** ![Craig\_White1](https://avatars.discourse-cdn.com/v4/letter/c/3ec8ea/32.png) [@Craig\_White1](https://discuss.rubyonrails.org/u/Craig_White1)\
**Post date:** [April 22, 2008, 12:01am UTC](https://discuss.rubyonrails.org/t/record-locking/28331/10 "2008-04-22T00:01:35Z")

</div>

> Craig -
> 
> \> \> \>\> \>\>\> It sounds as though you're worried about the record changing in \>\>\> between the user viewing the form and you saving the record. There's \>\>\> no support for that builtin, but I think you could extend the \>\>\> principle of optimistic locking (include the current lock\_version  
> \>\>\> as a \>\>\> hidden field on the form) \>\>\> \>\> ---- \>\> yeah - I sort of figured that out (the hidden field on the form  
> \>\> sending \>\> back the lock\_version value that it checked out) but this causes me a \>\> problem with validations now. \>\> \>\> Here's the issue in simplistic form... \>\> \>\> controller code... \>\> \>\> before optimistic locking \>\> \>\> if @client.update\_attributes(params[:client]) \>\> flash[:notice] = "Bravo" \>\> redirect\_to :back \>\> else \>\> flash[:notice] = @client.validate \>\> redirect\_to :back \>\> end \>\> \>\> NOW, with opportunistic locking... \>\> \>\> if whatever \>\> begin \>\> @client.update\_attributes(params[:client]) \>\> flash[:notice] = "Bravo" \>\> redirect\_to :back \>\> rescue \>\> flash[:notice] = "Something changed in the interim" \>\> redirect\_to :back \>\> end \>\> end \>\> \>\> The validate is lost in the rescue...how do I get my cake too? \> ---- \> I guess the question I am asking is if I have \> \> @client \> and params[:client] \> \> how do I validate @client with params[:client] modifications prior to \> saving it? \> \> Craig
> 
> @client.attributes = params[:client] @client.valid?

---

<div class="post-metadata">

**Author:** ![Lionel\_Bouton](https://avatars.discourse-cdn.com/v4/letter/l/a88e4f/32.png) [@Lionel\_Bouton](https://discuss.rubyonrails.org/u/Lionel_Bouton)\
**Post date:** [April 22, 2008, 8:45am UTC](https://discuss.rubyonrails.org/t/record-locking/28331/11 "2008-04-22T08:45:00Z")

</div>

Jodi Showers wrote:

> @client.attributes = params[:client] @client.valid?

isn't

@client.update\_attributes params[:client]

a shortcut for the example above ?

Lionel

---

<div class="post-metadata">

**Author:** ![Frederick\_Cheung](https://sea2.discourse-cdn.com/rubyonrails/user_avatar/discuss.rubyonrails.org/frederick_cheung/32/3901_2.png) [@Frederick\_Cheung](https://discuss.rubyonrails.org/u/Frederick_Cheung)\
**Post date:** [April 22, 2008, 11:01am UTC](https://discuss.rubyonrails.org/t/record-locking/28331/12 "2008-04-22T11:01:08Z")

</div>

No, since update\_attributes actually performs the save, whereas valid? will just run the validations.

Fred

---

<div class="post-metadata">

**Author:** ![Lionel\_Bouton](https://avatars.discourse-cdn.com/v4/letter/l/a88e4f/32.png) [@Lionel\_Bouton](https://discuss.rubyonrails.org/u/Lionel_Bouton)\
**Post date:** [April 22, 2008, 11:24am UTC](https://discuss.rubyonrails.org/t/record-locking/28331/13 "2008-04-22T11:24:39Z")

</div>

Frederick Cheung wrote:

> [...] No, since update\_attributes actually performs the save, whereas valid? will just run the validations.

Whoops. I had a feeling my question was stupid. Still need coffee...

---

<div class="post-metadata">

**Author:** ![Craig\_White1](https://avatars.discourse-cdn.com/v4/letter/c/3ec8ea/32.png) [@Craig\_White1](https://discuss.rubyonrails.org/u/Craig_White1)\
**Post date:** [April 22, 2008, 4:53pm UTC](https://discuss.rubyonrails.org/t/record-locking/28331/14 "2008-04-22T16:53:44Z")

</div>

> \> \> Jodi Showers wrote: \>\> \>\> @client.attributes = params[:client] \>\> @client.valid? \>\> \> \> isn't \> \> @client.update\_attributes params[:client] \> \> a shortcut for the example above ? No, since update\_attributes actually performs the save, whereas valid?  
> will just run the validations.
