In my app I created friend list for User. Inside Friend model I have validations for unique connection between users. Everything works good, but I don't know how to write tests for this model. It's looks like that:
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
When I try to run test I get error:
Failure/Error: unless (user1.friends.where(user2: user2) user1.is_friend.where(user1: user2)).blank?
NoMethodError:
undefined method `friends' for nil:NilClass
Why I get nil inside model? I did something wrong inside factory?
CodePudding user response:
What you actually want to find if Users 1 & 2 are friends is this query:
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
However the naming here is super off. The model should be named Friendship
as friend
actually means the person that you are friends with.