简体   繁体   中英

Rails: validate unique friendship relationships

I'm following http://railscasts.com/episodes/163-self-referential-association to make a friendship system.

#Friendship model
id | user_id | friend_id

The problem is

  1. How can I make the combination of user_id and friend_id unique? prevent creating user_id = 1, friend_id = 2 from user_id = 2. friend_id = 1

  2. I find this model design is really bad. Can I model it to actually store the combine of 2 ids? Like friendship_id_combination = [1, 2] , and then validate it.

You can use the following:

validate :users_are_not_already_friends

def users_are_not_already_friends
  combinations = ["user_id = #{user_id} AND friend_id = #{friend_id}",
  "user_id = #{friend_id} AND friend_id = #{user_id}"]
  if User.where(combinations.join(' OR ')).exists?
    self.errors.add(:user_id, 'Already friends!')
  end
end

Update 2019:

Revised suggestion:

def users_are_not_already_friends
  if User.where(user_id: friend_id, friend_id: user_id).exist?
    || User.where(user_id: user_id, friend_id: friend_id).exist?
    self.errors.add(:user_id, 'Already friends!')
  end
end

And I would strongly advise to add a DB constraint (unique index) based on the composite user_id and friend_id :

CREATE UNIQUE INDEX users_user_id_friend_id_key ON users (user_id, friend_id);

Why you need this unique combination. Consider if you want to fetch friends of single user then in current scenario you can find it using simple association.

@user.friends

And if you don't want to add two keys then you need to fire two queries to find same details. One for your friends and other for who requested you as a friend.

Yes. You are thinking along the right path. Perhaps the simplest solution is to use the database table to create the validation by making the combination of IDs a unique index.

class CreateFriendshipsUnq < ActiveRecord::Migration
  def change
    add_index :friendships, [:user_id, :friend_id], unique: true
  end
end

I think this will do what you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM