@ledsun blog

無味の味は佳境に入らざればすなわち知れず

楽観的ロックをあつかう編集画面

楽観的ロックを使ったRuby on Railsアプリケーションを作って動きを確かめる - @ledsun blog の続きです。

楽観的ロックで競合が起きるとActiveRecord::StaleObjectErrorが起きます。 エラー画面が表示されます。

編集画面に競合エラーを表示

ActiveRecord::StaleObjectErrorをハンドリングして次のように、編集画面にメッセージを表示してみましょう。

f:id:ledsun:20220413000516p:plain
フラッシュメッセージを表示して編集内容を復元します。

ArticlesController#update に例外処理を追加

つぎのように例外処理を追加します。

def update
  respond_to do |format|
    if @article.update(article_params)
      format.html { redirect_to article_url(@article), notice: "Article was successfully updated." }
      format.json { render :show, status: :ok, location: @article }
    else
      format.html { render :edit, status: :unprocessable_entity }
      format.json { render json: @article.errors, status: :unprocessable_entity }
    end
  end
rescue ActiveRecord::StaleObjectError
  @article.reload.attributes = article_params.reject{ _1 == 'lock_version' }

  flash.now[:error] = 'Another user has made a change to that record since you accessed the edit form.'
  render :edit, status: :conflict
end

やっていることは次の通りです。

  1. lock_versionを最新の値に更新
  2. 編集内容を復元
  3. フラッシュメッセージを設定
  4. 編集画面を表示

app/views/articles/edit.html.erb にフラッシュメッセージを追加

Scaffoldで生成した編集画面ではフラッシュメッセージが表示されません。 app/views/articles/edit.html.erbにフラッシュメッセージの表示を追加します。

<p style="color: red"><%= flash[:error] %></p>

<h1>Editing article</h1>

<%= render "form", article: @article %>

<br>

<div>
  <%= link_to "Show this article", @article %> |
  <%= link_to "Back to articles", articles_path %>
</div>

一番上の行です。

なにも考えずにUpdate Articleボタンを押すと更新されます。 別ユーザーが編集した内容を表示してあげると、より便利になりそうです。

参考