Railsのtransactionを試す

f:id:utouto97:20210725220657j:plain

utouto97.hatenablog.com

準備

以下のようなUserモデルを作成します。
validatesで:nameがユニークであることを確認します。

class User < ApplicationRecord
  validates :name, uniqueness: true
end

同名のユーザーを追加してみる

:nameがKenであるユーザーを追加します。

> User.create!(name: "Ken")

確認してみます。

>User.all.select("name")
  User Load (0.2ms)  SELECT "users"."name" FROM "users"
=> [#<User:0x000055c661df3310 id: nil, name: "Ken">]

:nameがKenのユーザーが追加されました。

もう一度追加してみます。

> User.create!(name: "Ken")
TRANSACTION (0.1ms)  begin transaction
  User Exists? (0.2ms)  SELECT 1 AS one FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "Ken"], ["LIMIT", 1]]
  TRANSACTION (0.1ms)  rollback transaction
/usr/local/bundle/gems/activerecord-6.1.4/lib/active_record/validations.rb:80:in `raise_validation_error': Validation failed: Name has already been taken (ActiveRecord::RecordInvalid)

上のようにエラーがでて追加できませんでした。
:nameが重複するので、はじかれたのです。

もちろん、この時点で、Kenというユーザーが一人いるだけです。

>User.all.select("name")
  User Load (0.2ms)  SELECT "users"."name" FROM "users"
=> [#<User:0x000055c661df3310 id: nil, name: "Ken">]

ApplicationRecord.transactionを試す

続いて、ApplicationRecord.transactionを使って、KenとBobを一気に追加してみます。

> ApplicationRecord.transaction do
>   User.create!(name: "Bob")
>   User.create!(name: "Ken")
> end
  TRANSACTION (0.1ms)  begin transaction
  User Exists? (0.1ms)  SELECT 1 AS one FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "Bob"], ["LIMIT", 1]]
  User Create (0.4ms)  INSERT INTO "users" ("name", "created_at", "updated_at") VALUES (?, ?, ?)  [["name", "Bob"], ["created_at", "2021-07-26 13:31:31.456418"], ["updated_at", "2021-07-26 13:31:31.456418"]]
  User Exists? (0.2ms)  SELECT 1 AS one FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "Ken"], ["LIMIT", 1]]
  TRANSACTION (0.3ms)  rollback transaction
/usr/local/bundle/gems/activerecord-6.1.4/lib/active_record/validations.rb:80:in `raise_validation_error': Validation failed: Name has already been taken (ActiveRecord::RecordInvalid)

Kenは既に存在するので、追加ができませんでした。
それと同時に、このトランザクションロールバックされ、Bobの追加も取り消されました。

確認してみると、Kenしか存在しません。

>User.all.select("name")
  User Load (0.2ms)  SELECT "users"."name" FROM "users"
=> [#<User:0x000055c661df3310 id: nil, name: "Ken">]

続いて、BobとJohnを追加してみます。

> ApplicationRecord.transaction do
>   User.create!(name: "Bob")
>   User.create!(name: "John")
> end

これはエラーにならずに追加されます。

確認してみると、Ken,Bob,Johnの3人が存在します。

> User.all.select(:name)
  User Load (0.2ms)  SELECT "users"."name" FROM "users"
=> 
[#<User:0x000055866e0d2330 id: nil, name: "Ken">,
 #<User:0x000055866e0d2268 id: nil, name: "Bob">,
 #<User:0x000055866e0d21a0 id: nil, name: "John">]

終わり