0

У меня есть модель пользователя, и я хочу создать дружбу между пользователями. Я достиг этого с помощью has_and_belongs_to_manyBi-Directional has_and_belongs_to_many на одной модели в Rails

has_and_belongs_to_many :friends, class_name: 'User', foreign_key: :friend_id 

И у меня есть таблица для этой ассоциации:

create_table :users_users do |t| 
    t.uuid :user_id, null: false 
    t.uuid :friend_id, null: false 
    t.timestamps 
end 

Когда я получаю друг через user.friends мне нужно иметь ассоциацию, где текущий пользователь находится в user_id колонки или friend_id. Мое текущее решение возвращает мне только записи, где пользователь находится в таблице friend_id.

У меня есть два решения для этого:

  1. повторяющиеся записи [{идентификатор_пользователя: 1, friend_id: 2}, {идентификатор_пользователя: 2, friend_id: 1}]
  2. Override метод user.friends и возврат мой пользовательский запрос

Оба решения не являются элегантными и оптимальными.

Об этом я читал article, но решение этой статьи очень сложно.

Есть ли другие решения этой проблемы? Я использую рельсы. 5.

ответ

0

Прежде всего, я скорее использую эту статью или один запрос, чтобы получить все записи вместо этого.

Активный запись способ сделать это:

  1. создать has_many отношений вместо HABTM отношений
  2. запроса users_users таблицы, чтобы найти все записи, которые соответствуют user_id=my_user.id или friend_id=my_user.id
  3. расплющить результат
  4. их уникальные
  5. re перемещения текущего пользователя из массива

поэтому я предлагаю положить этот метод в модели пользователя:

def all_friends 
    UserFriend.includes(:user, :friend).where("user_id=? OR friend_id=?", id , id).map {|rel| [rel.user, rel.friend] }.flatten.uniq{|u| u.id}.reject{|u| u.id == self.id} 
end 

UserFriend модель:

class CreateUserFriends < ActiveRecord::Migration[5.0] 
    def change 
    create_table :user_friends do |t| 
     t.belongs_to :user, foreign_key: true 
     t.belongs_to :friend, foreign_key: 'friend_id', class: 'User' 

     t.timestamps 
    end 
    end 
end 
+0

Недостатком метода, в отличие от ассоциаций и областей, является то, что в некоторых ситуациях их сложнее повторно использовать при использовании 'merge' и связанных с ним механизмов. –

+0

@ma_il согласен. Я не поклонник этой техники, но она работает. –

0

Не 100% уверен, что это будет работать, но по-прежнему хотел дайте это вам, чтобы попробовать, прежде чем я получу очень необходимый сон;) Укажите способ пользовательских запросов к вашей ассоциации:

has_and_belongs_to_many :friends, -> { 
    where("friend_id = :user_id OR user_id = :user_id", user_id: id) 
}, class_name: 'User', foreign_key: friend_id 
+0

Это не сработает, потому что рельсы используют внутреннее соединение для извлечения этих записей, и этот запрос будет объединен с оригинальным.Теперь запрос выглядит так: 'SELECT COUNT (*) FROM« users »INNER JOIN« users_users »ON« users ».« Id »=« users_users ».« User_id »WHERE« users_users ».« Friend_id »= $ 1 AND (friend_id = '96b232eb-43ea-4eaa-9f47-9eae0516fde2' OR user_id = '96b232eb-43ea-4eaa-9f47-9eae0516fde2') [["friend_id", "96b232eb-43ea-4eaa-9f47-9eae0516fde2"]] ' –

+0

Ну которые все еще могут быть исправлены путем явного добавления имени таблицы соединений в запрос. –