railsで楽観的ロック

railsで楽観的ロックを実現する方法について記載します。

ほぼ下記リンクの通りでできた気がするけど、復習のため。

Ruby on Rails 備忘録 – Ride On Rails » Blog Archive » ActiveRecordによる楽観的ロック

 

とりあえず、lock_versionカラムを追加する

$ rails generate migration add_lock_version_to_reserves lock_version:integer

 migrationファイルが作成されるので以下のような感じにする。

class AddLockVersionToReserves < ActiveRecord::Migration
  def change
    add_column :reserves, :lock_version, :integer, default: 0
  end
end

フォームがあるビューには以下のようにhidden_field_tagでlock_versionを渡すようにする。

<%= form_for @reserve do |f|  %>
  <%= f.hidden_field :lock_version %>

 lock_versionカラムの存在によって、更新時にlock_versionの値が書き換わっていた場合はActiveRecord::StaleObjectError例外が発生するようになり、これをrescueすることでロールバックが行えるようになる。

def update
  @reserve = Reserve.find(params[:id])
  ActiveRecord::Base.transaction do
    @reserve.update_attributes!(params[:reserve])
  end

  redirect_to reserves_path, notice: message

  rescue ActiveRecord::StaleObjectError
    redirect_to reserves_path, alert: "他の人によって変更されました。"
  rescue => e
    puts e
    puts e.backtrace
    redirect_to reserves_path
end

ちなみにupdate_attributesだと楽観的ロックが効くけど、saveだと効かないので注意!