I have an app where I need to prevent users from editing data while it is being edited by a different user. I'm trying to think of the best way to do it and wanted to ask for ideas. So far, I've created a settings model that stores application wide configuration on the db in key/value pairs. So, for the lock, I have a settings instance that's called LOCKED_TABLE_UID, and it stored the user_id of the user editing the table or null (nil) if the table is free.
>> lock = Setting.find_by_key('LOCKED_TABLE_UID')
Then, I implemented 2 methods in my application controller to acquire and release the lock:
# current_user returns the user currently logged in
def acquire_lock
lock = Setting.find_by_key("LOCKED_TABLE_UID")
if lock.value
# if lock taken, see if it's the current_user or someone else
if lock.value.to_i == current_user.id.to_i
return true
else
return false
end
else
# lock is free, assign it to this user
lock.value = current_user.id
return true if lock.save
end
end
def release_lock
lock = Setting.find_by_key("LOCKED_TABLE_UID")
if lock.value
# the lock belongs to current_user, so he can release it
if lock.value.to_i == current_user.id.to_i
lock.value = nil
return true if lock.save
else
# not your lock, go away
return false
end
else
# lock is free, quit bugging
return true
end
end
What I want is to create some kind of block code that contains the locking mechanism, something like this:
def some_crud_action
requires_locking do |lock|
if lock
# do some CRUD stuff here
else
# decline CRUD and give some error
end
end
end
I'd appreciate help on this - but I'm also open to other suggestions on how to accomplish all that, or some things I may have overlooked. This lock doesn't have to be atomic, but fairly basic and most important - that it works :) thanks.
Have you seen the ActiveRecord built-in locking feature?
You're almost there. Create your require_locking? action as you see fit. Then process it with a before_filter.
before_filter :requires_locking?, :only => [:update, :destroy]
after_filter :release_lock, :only => [:update, :destroy]
def requires_locking do |lock|
unless acquire_lock
lock = Setting.find_by_key("LOCKED_TABLE_UID")
user_with_lock = User.find(lock.value)
flash[:message] = "Action denied: Table locked by: #{user_with_lock.name}"
redirect_to :back
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With