record locking

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

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!

> > 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

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.

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.

> 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?

  id = params[:id]   if id && @client.valid?     begin       @client.update_attributes(params[:client])       flash[:notice] = 'Client was successfully updated.'       redirect_to :back     rescue       flash[:notice] = "Client record was changed by someone else \         while you were editing and you will have to edit again, \         starting over"       redirect_to :back     end   else     flash[:notice] = "Danger Will Robinson"     redirect_to :back   end

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

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)

> 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?

Craig -

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?

Jodi Showers wrote:

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

isn't

@client.update_attributes params[:client]

a shortcut for the example above ?

Lionel

No, since update_attributes actually performs the save, whereas valid? will just run the validations.

Fred

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...

> > 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.