Rspec 架空モデルのアソシエーション

##投稿背景
架空モデルが関係する部分でテストを実装していたところ、架空モデルの定義でエラーが解決できずにいて手こずっていたが、なんとか解決できたので備忘録として投稿

##実装する機能
・チャット機能
・通知機能←こいつが強敵でした


##モデルのアソシエーション
touristとguide、２種類のユーザー間で通知機能を実装するためのアソシエーション。

```chat_notice.rb
belongs_to :guide_visitor, class_name: 'Guide', foreign_key: 'visitor_id', optional: true
belongs_to :guide_visited, class_name: 'Guide', foreign_key: 'visited_id', optional: true
belongs_to :tourist_visitor, class_name: 'Tourist', foreign_key: 'visitor_id', optional: true
belongs_to :tourist_visited, class_name: 'Tourist', foreign_key: 'visited_id', optional: true
```


```tourist.rb
has_many :tourist_active_notices, class_name: 'ChatNotice', foreign_key: 'visitor_id', dependent: :destroy
has_many :tourist_passive_notices, class_name: 'ChatNotice', foreign_key: 'visited_id', dependent: :destroy
```


```guide.rb
has_many :guide_active_notices, class_name: 'ChatNotice', foreign_key: 'visitor_id', dependent: :destroy
has_many :guide_passive_notices, class_name: 'ChatNotice', foreign_key: 'visited_id', dependent: :destroy
```


##factory
```chat_notice.rb
FactoryBot.define do
    factory :chat_notice do
        association :chat
        association :guide_visitor
        association :guide_visited
        association :tourist_visitor
        association :tourist_visited
    end
end
```


##実行したテスト
```chat_notice.rb
require 'rails_helper'

RSpec.describe ChatNotice, type: :model do
	let(:chat) { create(:chat) }
	let(:room) { create(:room) }
	let(:guide_visitor) { create(:guide) }
	let(:guide_visited) { create(:guide) }
	let(:tourist_visitor) { create(:tourist) }
	let(:tourist_visited) { create(:tourist) }
	let!(:chat_notice) { build(:chat_notice, chat_id: chat.id, visited_id: tourist_visited.id, visitor_id: guide_visitor.id) }


	describe 'ChatNotice保存テスト' do
        context 'チャット通知が正しく保存される' do
		    it '全て入力されているので保存' do
		        expect(chat_notice).to be_valid
		    end
    	end
    end

    describe 'ChatNoticeアソシエーションのテスト' do
        context 'Tourist_visitorモデルとの関係' do
            it 'N:1となっている' do
                expect(ChatNotice.reflect_on_association(:tourist_visitor).macro).to eq :belongs_to
            end
        end
        context 'Tourist_visitedモデルとの関係' do
            it 'N:1となっている' do
                expect(ChatNotice.reflect_on_association(:tourist_visited).macro).to eq :belongs_to
            end
        end
        context 'Guide_visitorモデルとの関係' do
            it 'N:1となっている' do
                expect(ChatNotice.reflect_on_association(:guide_visitor).macro).to eq :belongs_to
            end
        end
        context 'Guide_visitedモデルとの関係' do
            it 'N:1となっている' do
                expect(ChatNotice.reflect_on_association(:guide_visited).macro).to eq :belongs_to
            end
        end
	end
end
```


##　エラー内容
こんな感じでキーが見つからないよーっていうエラーが出る。

```ruby:
# KeyError:
     #   key not found: "guide_visitor"
```


guide_visitorはguideモデルを基に定義された架空のモデルだから、factoryにguideを定義していればテストは通ると思ってたけど、失敗。


##　原因
factory の定義の中で association を定義するということはその同名の factory が存在すること前提になってるみたいで、guide_visitorをfactoryに定義してなかったからエラーが発生してた。


##　解決方法　：　factory:キーワード引数
factory の association 定義に対して、それが利用することになる association 先の factory の名前を別のものにしたい場合には**factory:キーワード引数**で指定してやる

```ruby:
FactoryBot.define do
    factory :chat_notice do
        association :chat
        association :guide_visitor, factory: :guide　　#factory: :guideを追加
        association :guide_visited, factory: :guide　　#factory: :guideを追加
        association :tourist_visitor, factory: :tourist　　#factory: :touristを追加
        association :tourist_visited, factory: :tourist　　#factory: :touristを追加
        checked { Faker::Boolean.boolean }
    end
end
```