Rails5+複合主キーでやっていくにはcomposite_primarykeyが必要ですが
テストコードを書く際にハマったのでその時のメモを残しておきます
FactoryBotでテストデータを作成する際の話です
composite_prrimarykeyを使ってreportsテーブルを複合主キーで扱うことにしています
- migrate
def change
create_table :reports, primary_key: ['id', 'date'] do |t|
t.bigint :id, null: false, auto_increment: true
t.date :date, null: false
t.integer :hoge, null: true
t.timestamps
end
end
- app/models/report.rb
modelで明示的に主キーをid,dateと指定しています
class Report < ApplicationRecord self.primary_keys = :id, :date end
- spec/factories/report.rb
テスト用のデータ部分を記述します
FactoryBot.define do
factory :report do
sequence(:id) {|n| n}
sequence(:date) {|n| Date.today.subtract }
....
....
....
....
end
end
- spec/models/report_spec.rb
簡単なテストコードを書いてみます
RSpec.describe Report, type: :model do
describe 'sample' do
before(:each) do
FactoryBot.create_list(:report, 2)
end
context 'hoge' do
it do
expect(Report.all.size).to eq(2)
end
end
end
end
実行するとエラーが出ます
Failures:
1) Report sample hoge
Failure/Error: let(:row) { FactoryBot.create(:report) }
ArgumentError:
Unsupported type: 1
簡単に抜粋だけしましたがこれだと上記エラーが出てきます
ただArgumentError: Unsupported type: しかでてきません
ソース追ってみると該当箇所の主キーの渡し方が違うようです
def self.parse(value)
case value
when Array
value.to_composite_keys
when String
self.new(value.split(ID_SEP))
else
raise(ArgumentError, "Unsupported type: #{value}")
end
end
このparseはArrayかStringしか受け付けないようになっています
なので配列で渡すか、1,2というふうに区切り文字で区切って渡す方法が用意されているようです
それに対応させて渡してあげれば良いわけですね
今回はidをid,dateで指定しているので同じようにテストデータ作成時もidに対して渡して上げる必要があるようです
後でREADME見てみたら普通にのっていたのでちゃんと読めって話ではあるのですがいつもパーティションはった複合主キーのテーブルに対してはactiverecord-importでしかデータ入れてなかったためちょっとはまりました
なのでこんな感じでデータを作ってあげるようにすれば良い感じです
- spec/factories/report.rb
sequence(:id) {|n| [n, Date.today]}
おわり