Rspec - 在同一列中有两个关联的测试模型

Rspec - test model that has two associations two the same column

在我的应用程序中,我为用户创建了好友列表。在 Friend 模型中,我验证了用户之间的独特联系。一切正常,但我不知道如何为这个模型编写测试。看起来像这样:

Friend.rb

class Friend < ApplicationRecord
  belongs_to :user1, :class_name => 'User'
  belongs_to :user2, :class_name => 'User'

  validate :uniqueness_of_users_associations, :cant_be_friend_with_yourself

  def uniqueness_of_users_associations
    unless (user1.friends.where(user2: user2) + user1.is_friend.where(user1: user2)).blank?
      errors.add(:friend, 'He is already your friend')
    end
  end

  def cant_be_friend_with_yourself
    errors.add(:friend, "You can't be friend with yourself") if user1 == user2
  end
end

User.rb:

class User < ActiveRecord::Base
  extend Devise::Models 

  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  include DeviseTokenAuth::Concerns::User

  has_many :friends, :class_name => 'Friend', :foreign_key => 'user1', dependent: :destroy
  has_many :is_friend, :class_name => 'Friend', :foreign_key => 'user2', dependent: :destroy
end

spec/factories/friends.rb :

FactoryBot.define do
  factory :friend do
    association :user1, factory: :user
    association :user2, factory: :user
    confirmed { true }
  end
end

friend_spec.rb :

RSpec.describe Friend, type: :model do
  describe 'relationships' do
    it { is_expected.to belong_to(:user1).class_name('User') }
    it { is_expected.to belong_to(:user2).class_name('User') }
  end
end

当我尝试 运行 测试时出现错误:

Failure/Error: unless (user1.friends.where(user2: user2) + user1.is_friend.where(user1: user2)).blank?
     
     NoMethodError:
       undefined method `friends' for nil:NilClass

为什么我在模型中得到 nil?我在工厂里做错了什么?

如果用户 1 和 2 是朋友,您实际想要查找的是以下查询:

EXISTS (
 SELECT 1 
 FROM friends
 WHERE 
     friends.user1_id = 1 OR friends.user2_id = 1 
   AND 
     friends.user1_id = 2 OR friends.user2_id = 2
)
class Friend < ApplicationRecord

  validate :uniqueness_of_users_associations, :cant_be_friend_with_yourself

  def uniqueness_of_users_associations
    if Friend.between(user1.id, user2.id).exists?
      errors.add(:base, 'Friendship already exists')
    end
  end

  def self.between(a, b)
    user1_id, user2_id = arel_table[:user1_id], arel_table[:user2_id]
    where(user1_id.eq(a).or(user2_id.eq(a)))
    .where(user1_id.eq(b).or(user2_id.eq(b))) 
  end
  # ...
end

不过这里的命名太离谱了。该模型应命名为 Friendship,因为 friend 实际上表示与您成为朋友的人。