Rspecの関連まわりで「バリデーションに失敗しました」が発生するとき

# 問題
`User has_many Cup(s)`
`Cup belongs_to User`
という関連を作成したあと、以下のようなFactoryを作成。

users.rb

```ruby:spec/factories/users.rb
FactoryBot.define do

  factory :user do
    name { "user" }
    email { "user@example.com" }
    password { "test123" }
    password_confirmation { "test123" }
  end

end
```

cups.rb

```ruby:spec/factories/cups.rb
FactoryBot.define do

  factory :cup do
    user
    comment { "This is my cup" }
  end

end
```


cups.rbのfactory :cupの中に、`user`を記載している。


この状態で、テストに以下のような記載をすると
`バリデーションに失敗しました`のエラーが発生してしまう。


```ruby:
describe "GET #index" do
  context "with user" do
    let(:user) { create(:user) }
    let(:cup) { create(:cup) }

    before do
      sign_in(user)
    end

    it "gets response 200" do
      expect(response.status).to eq 200
    end

    # 以下itから始まるテストが続く
    # ここでは省略する

  end
end
```

```ruby:
[1] pry(<RSpec::ExampleGroups::UserCupsResponse::POSTCreate::WithUser>)> cup
ActiveRecord::RecordInvalid: バリデーションに失敗しました: Emailはすでに存在します, Nameはすでに存在します
from /Users/reiforu/dev/cofapp/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.3/lib/active_record/validations.rb:80:in `raise_validation_error'
```

`name`と`error`はuser.rbのカラムで、`models/user.rb`にて
どちらも`uniqueness: true`を付与している。


# 私の解決法

`let(:cup) { create(:cup) }`でバリデーションエラーが出たってことは、
`user`が既に作られているということ？

けど、`cup.rb`には`user`を記載して関連づけたし、この`user`は存在しなければならない。
だから、`let(:user)`も記載しなくちゃいけないよな。。

<br>

あ、でもここで<b>`let(:user)`して既に`user`ができちゃってるのがダメなのかも。。</b>

試しに`let(:user)`消してみよう。


```ruby:
describe "GET #index" do
  context "with user" do
    let(:cup) { create(:cup, user: user) }
```

```ruby:
1] pry(<RSpec::ExampleGroups::UserCupsResponse::POSTCreate::WithUser>)> cup
+----+-------------------------+-------------------------+----------------+---------+
| id | created_at              | updated_at              | comment        | user_id |
+----+-------------------------+-------------------------+----------------+---------+
| 3  | 2019-05-12 05:37:28 UTC | 2019-05-12 05:37:28 UTC | This is my cup | 1       |
+----+-------------------------+-------------------------+----------------+---------+
1 row in set
```

登録できた！

てことは、<b>`cup作成時にuserというfactoryを【新たに】作成する`</b>ってことか。<b>

`cup.rb`に`user`を記載して関連付けを定義したから、
<b>その`user`を別途`let(:user)`として呼び出さなきゃいけないと思ってた。。</b>



# けど

これだと<b>`before〜do`内の`sign_in(user)`の`user`が`nil`になってログインできない。。</b>


よし、じゃあ試しに`let(:user)`を記載した上で、
`let(:cup)`に`user`を付与してみよう。

```ruby:
describe "GET #index" do
  context "with user" do
    let(:user) { create(:user) }
    let(:cup) { create(:cup, user: user) }
```

```ruby:
[1] pry(<RSpec::ExampleGroups::UserCupsResponse::POSTCreate::WithUser>)> cup
+----+-------------------------+-------------------------+----------------+---------+
| id | created_at              | updated_at              | comment        | user_id |
+----+-------------------------+-------------------------+----------------+---------+
| 3  | 2019-05-12 05:21:12 UTC | 2019-05-12 05:21:12 UTC | This is my cup | 1       |
+----+-------------------------+-------------------------+----------------+---------+
1 row in set
```

登録できたー！そして、`sign_in(user)`もうまく実行できた。


# まとめ

```ruby:spec/factories/cups.rb
FactoryBot.define do

  factory :cup do
    user
    comment { "This is my cup" }
  end

end
```

`factory`に上記`user`のような定義をした場合、

● `cup`インスタンスの作成時に<b>新たに</b>`user`を作成し、関連づける。
→<b>この際、`let(:user)`などを定義していて既に同じ`user`がいるとバリデーションエラーが発生する。</b>

●しかし、`sign_in(user)`のように、引数にどうしても`user`が必要な際は、
<b>テスト内でlet(:user)を作成し、その`user`を`cup`に関連付ける。</b>

```ruby:
    # こんな感じ
    let(:user) { create(:user) }
    let(:cup) { create(:cup, user: user) }
```

<br>

おわり