edit conflict snippets

Optimistic locking in Rails

Tagged edit conflict, optimistic lock, optimistic locking, rails  Languages ruby, slim

This code is an adaptation of the code found in this Railscasts article: http://railscasts.com/episodes/59-optimistic-locking-revised?view=asciicast

app/models/concerns/optimistic_locking.rb

module OptimisticLocking
  extend ActiveSupport::Concern

  included do
    validate :handle_conflict, on: :update
  end

  def original_updated_at
    @original_updated_at || updated_at.to_f
  end
  attr_writer :original_updated_at

  def handle_conflict
    return unless @conflict || updated_at.to_f > original_updated_at.to_f

    @conflict = true
    # By setting original_updated_at to nil the edit conflict is ignored on a second form submit
    @original_updated_at = nil

    errors.add :base, I18n.t('activerecord.edit_conflict.message')
    changes.each do |attribute, values|
      errors.add(
        attribute,
        I18n.t('activerecord.edit_conflict.was', value: values.first)
      )
    end
  end
end

app/models/project.rb

class Project < ApplicationRecord
  include OptimisticLocking

app/views/_edit_conflict.slim

- object.errors[:base]&.each do |error|
  p.text-danger
    = icon('fas', 'exclamation-circle')
    =< error

app/views/projects/_form.slim

= form @project do |f|
  = render '/edit_conflict', object: @project
  = f.hidden_field :original_updated_at
  = f.text_field :name, class: 'form-control'
  = form_buttons(f, @project)