[Ruby] Lock_version may be used for tables that tend to access and edit the same record at the same time.

2 minute read

Introduction

I was interested in reading the Rails Guide, so I actually touched it. The memo.

When A and B edit the same record in the application, if the same record is accessed at exactly the same timing, A updates the record and then B updates B. B edits A. Will be overwritten without checking. If this is an update of the same attribute, but if it is another attribute, the edit will be rewound, which is a bad situation.

A lock_version is provided in Active Record for this issue. lock_version adds a column that plays a role of the edit history count of the instance to the table and refers to the value. If you use lock_version, you can put an error in the above case.

how to use

To use it, create a column called lock_version in the table.

.rb


t.integer :lock_version, default: 0

Operation check

p1 = Memo.find(1)
p2 = Memo.find(1)
# => #<Memo id: 1, text: "hello", lock_version: 0>

Obviously lock_version is 0 at the time of calling Then update p1.

p1.update(text:'good bye')
# => #<Memo id: 1, text: "good bye", lock_version: 1>

SQL


   (0.3ms) BEGIN
  Memo Update (13.4ms) UPDATE `memos` SET `text` ='good bye', `lock_version` = 1 WHERE `memos`.`id` = 1 AND `memos`.`lock_version` = 0
   (3.9ms) COMMIT

look_version has been rewritten to 1. You can also see that the SQL condition for update has lock_version = 0. Next, let’s update p2. The lock_version of the p2 instance remains 0 because it has not been reloaded.

p2.update(text:'say hello')
# => ActiveRecord::StaleObjectError (Attempted to update a stale object: Memo.)

SQL


   (0.7ms) BEGIN
  Memo Update (1.0ms) UPDATE `memos` SET `text` ='say hello', `lock_version` = 1 WHERE `memos`.`id` = 1 AND `memos`.`lock_version` = 0
   (2.4ms) ROLLBACK

I am getting an error properly. I think that SQL itself does not appear even if an error is executed, so it seems that it is returning an error as a trigger that there is no affected row on rails side? I will not read the source this time, so if you have read it, please share it!

Operation check (Web)

As per RailsApi, let’s put lock_version in the form as a hidden parameter. Without this, the backend will not be able to compare the lock_version and no error will occur.

<input type="hidden" value="2" name="memo[lock_version]" id="memo_lock_version">

After adding the above, opening two tabs to edit the same record and updating each tab, the one who updated later got an error safely. Screenshots 2020-07-26 11.22.12.png

After that, let’s handle this again by error handling as in RailsApi. There are various ways to deal with this.

  • If two people edit different attributes, update them in order and when the same attribute is edited, display it on the screen and ask the user
  • Make sure that other attributes updated by a person before you are not affected and then update

And. I wonder if this area is just a matter of how the data is used on the app.

Finally

I’ve never used it in practice, so I’d be happy if you could share it like “I’m doing this in my house!”!

Reference article

Rails Guide What is Optimistic Locking