RSpec FactoryBot验证失败多对多关系

时间:2019-05-31 01:35:14

标签: ruby-on-rails factory-bot rspec-rails

运行以下规格时,我一直得到ActiveRecord::RecordInvalid: Validation failed: Role must exist

我基本上是想将创作者添加到歌曲中。信用记录即为数据库中的联接表。现在,信用表还具有一个列role_id,该列属于Roles表。但是我不知道如何创建角色记录,以便在将创建者添加到歌曲后就存在。以下代码的完整细分。

规格:

describe '.get' do
        before :each do 
            @song = create(:song)
            @creator = create(:creator)
            @song.creators << @creator    
        end
end

型号:

class Credit < ApplicationRecord
  belongs_to :song
  belongs_to :creator
  belongs_to :role 
end


class Song < ApplicationRecord
  has_many :credits
  has_many :creators, through: :credits
end



class Creator < ApplicationRecord
    has_many :credits
    has_many :songs, through: :credits
end

class Role < ApplicationRecord
end

工厂:

FactoryBot.define do 
    factory :song do 
        name { Faker::Music::Phish.song }
        uri {"spotify:track:#{SecureRandom.alphanumeric(22)}"}
        current_popularity {rand(0..100)}
        master {1}
        credits_checked {0}
        credits_verified {0}
        credits_approved {0}
        checked {0}
        created_at {Time.now - rand(3..30).days}
        updated_at {Time.now - 1.days} 
    end
end


FactoryBot.define do 
    factory :creator do 
        name { Faker::Name.name }
        claimed {0}
        created_at {Time.now - rand(10..30).days}
        updated_at {Time.now - rand(1..5).days}
    end
end

FactoryBot.define do
    factory :credit do 
        creator
        song
        role { create(:role) }
        active {1}
        display {1}
        created_at {Time.now - rand(10..30).days}
        updated_at {Time.now - rand(1..5).days}

    end
end

FactoryBot.define do 
    factory :role do 
        name {'Writer'}
        ordering {1}
        created_at {Time.now}
        updated_at {Time.now}
    end
end

1 个答案:

答案 0 :(得分:0)

由于您在Credit模型中拥有第三个belongs_to,并且这是必需的,因此您无法使用默认的Rails方式<<添加关联的记录。您在这里有两个选择:

  1. 使角色关联为可选,并在创建后将角色分配给功劳

    belongs_to :role, optional: true
    
    before :each do 
      @role = create(:role)
      @song = create(:song)
      @creator = create(:creator)
      @song.creators << @creator  
      @song.credits.find_by(creator: @creator).update(role: @role)  
    end
    
  2. 无需<<运算符即可显式创建信用额

    before :each do 
      @role = create(:role)
      @song = create(:song)
      @creator = create(:creator)
      @song.credits.create(creator: @creator, role: @role)  
    end
    

我认为,第二个比较好,因为您可以保留角色验证并在一个操作中创建信用实例。