LoginSignup
0

posted at

FactoryBotでcreate(:client)時にActiveRecord::RecordNotUniqueが発生する

コード

  • spec/models/client_spec.rb
require 'rails_helper'

RSpec.describe Client, type: :model do
  it "is valid with default" do
    client = FactoryBot.create(:client)
    expect(client).to be_valid
  end
end
  • spec/models/client_spec.rb
FactoryBot.define do
  factory :client do
    sequence(:id) { |n| n } # シーケンスを使う
    sequence(:name) { |n| "クライアント#{n}" }
    created_at { Time.current }
    updated_at { Time.current }
  end
end

概要

タイトルの通りだが、上記のコードでrspecを実行すると以下のエラーが発生する

Running via Spring preloader in process 160
F

Failures:

  1) Client is valid with default
     Failure/Error: client = FactoryBot.create(:client)

     ActiveRecord::RecordNotUnique:
       Mysql2::Error: Duplicate entry '1' for key 'clients.PRIMARY'
     # /usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:131:in `_query'
     # /usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:131:in `block in query'
     # /usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:130:in `handle_interrupt'
     # /usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:130:in `query'
     # /usr/local/bundle/gems/rack-mini-profiler-2.3.4/lib/patches/db/mysql2/alias_method.rb:22:in `query'
     # /usr/local/bundle/gems/factory_bot-6.2.1/lib/factory_bot/evaluation.rb:18:in `create'
     # /usr/local/bundle/gems/factory_bot-6.2.1/lib/factory_bot/strategy/create.rb:12:in `block in result'
     # /usr/local/bundle/gems/factory_bot-6.2.1/lib/factory_bot/strategy/create.rb:9:in `tap'
     # /usr/local/bundle/gems/factory_bot-6.2.1/lib/factory_bot/strategy/create.rb:9:in `result'
     # /usr/local/bundle/gems/factory_bot-6.2.1/lib/factory_bot/factory.rb:43:in `run'
     # /usr/local/bundle/gems/factory_bot-6.2.1/lib/factory_bot/factory_runner.rb:29:in `block in run'
     # /usr/local/bundle/gems/factory_bot-6.2.1/lib/factory_bot/factory_runner.rb:28:in `run'
     # /usr/local/bundle/gems/factory_bot-6.2.1/lib/factory_bot/strategy_syntax_method_registrar.rb:28:in `block in define_singular_strategy_method'
     # ./spec/models/client_spec.rb:5:in `block (2 levels) in <top (required)>'
     # ------------------
     # --- Caused by: ---
     # Mysql2::Error:
     #   Duplicate entry '1' for key 'clients.PRIMARY'
     #   /usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:131:in `_query'

Finished in 0.06375 seconds (files took 4 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/models/client_spec.rb:4 # Client is valid with default

原因

  • Mysql2::Error: Duplicate entry '1' for key 'clients.PRIMARY' つまり、clientsのidが他のケースと重複しているため
  • FactoryBotのGitHubのページに以下のような記述があり、自分としてはFactoryBotはfixtureの代替であるため、fixtureの書き方を踏襲するものだと思った

factory_bot is a fixtures replacement
(訳: factory_bot はフィクスチャの代替品です。)

  • そのため spec/models/client_spec.rb にはidやcreated_at、updated_atといったDBで採番されるものをコードに書いていた。
  • しかしFactoryBotのWrong Wayとしても紹介されているが、独自SEQUENCE IDとして推奨されていない

対処

  • spec/models/client_spec.rbで独自SEQUENCE IDなコードを削除する
FactoryBot.define do
  factory :client do
    sequence(:name) { |n| "クライアント#{n}" }
  end
end
  • テストを実行し、passすることを確認
root@99008ab20f76:/app# rspec spec/models/client_spec.rb
Running via Spring preloader in process 181
.

Finished in 0.09304 seconds (files took 4.34 seconds to load)
1 example, 0 failures

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0