module ActiveRecord::Locking::Pessimistic

def lock!(lock = true)

the locked record.
or pass true for "FOR UPDATE" (the default, an exclusive row lock). Returns
lock. Pass an SQL locking clause to append the end of the SELECT statement
Obtain a row lock on this record. Reloads the record to obtain the requested
def lock!(lock = true)
  if persisted?
    if has_changes_to_save?
      raise(<<-MSG.squish)
        Locking a record with unpersisted changes is not supported. Use
        `save` to persist the changes, or `reload` to discard them
        explicitly.
      MSG
    end
    reload(lock: lock)
  end
  self
end

def with_lock(*args)

ActiveRecord::ConnectionAdapters::DatabaseStatements#transaction).
and joinable: to the wrapping transaction (see
You can also pass options like requires_new:, isolation:,

as an optional argument (see #lock!).
before yielding. You can pass the SQL locking clause
Wraps the passed block in a transaction, locking the object
def with_lock(*args)
  transaction_opts = args.extract_options!
  lock = args.present? ? args.first : true
  transaction(**transaction_opts) do
    lock!(lock)
    yield
  end
end