Самореферентный поиск в отношениях количества контроллеров

У меня возникли серьезные проблемы с извлечением набора записей, которые самореферентно связаны с пользователем, чтобы показать их на странице «показать» пользователя.

Вот идея:

Пользователи (current_user) оценивают совместимость двух других пользователей (user_a и user_b). Они могут оценивать совместимость как положительно, так и отрицательно: оценка двух пользователей как «совместимых» создает positive_connection между user_a и user_b, а оценка их как «несовместимых» создает negative_connection. Итак, есть модели для Positive_Connection, Negative_Connection и User.

Теперь мне нужно отображать только пользователей overall_positively_connected_to(@user) (т.е. где positive_connections_to(@user).count > negative_connections_to(@user).count).

Вот где я должен, но я не могу двигаться дальше:

Пользовательская модель:

  def overall_positive_connected_to(user)
      positive_connections_to(user).count > negative_connections_to(user).count
  end


  def positive_connections_to(user)
      positive_connections.where("user_b_id = ?", user)
  end     

  def negative_connections_to(user) 
      negative_connections.where("user_b_id = ?", user)
  end

Контроллер

@user.user_bs.each do |user_b|
  if user_b.overall_pos_connected_to(@user)
    @compatibles = user_b
  end
end

Код в контроллере явно неправильный, но как мне это сделать? Я совершенно новичок в рельсах (и sql), поэтому, возможно, сделал что-то наивное.

Любая помощь будет здорово.


person jonic    schedule 11.06.2011    source источник


Ответы (1)


Я правильно понимаю, что у вас 3 модели?

  • Пользователь (id, имя)
  • PositiveConnection (user_a_id, user_b_id)
  • Отрицательное соединение (user_a_id, user_b_id)

Или что-то в этом роде.

Я думаю, вам просто нужны 2 модели, и для удобства я собираюсь переименовать отношения как «from_user» и «to_user».

  • Пользователь (id, имя)
  • Соединение (значение: целое число, from_user_id, to_user_id)

Где значение равно -1 для отрицательного значения и +1 для положительного.

Теперь мы можем сделать что-то вроде (примечание: вам нужно разобраться с точным синтаксисом, например, :foreign_key, :source и так далее)

class User

  has_many :connections, :foreign_key => "from_user_id"
  has_many :connected_users, :through => :connections, :source => :to_user

  def positive_connections
    connections.where(:value => 1)
  end

  def negative_connections
    ...
  end

end

Но у нас также теперь есть фреймворк для создания сложного sql-запроса (опять же нужно заполнить пробелы... но что-то вроде)

class User

  def positive_connected_users
    connected_users.joins(:connections).group("from_user_id").having("SUM(connections.value) > 0")
  end

end

это не совсем сработает, но это своего рода псевдокод для реального решения

(может быть, лучше думать в терминах чистого sql)

SELECT users.* FROM users
INNER JOIN connections ON to_user_id = users.id
WHERE  from_user_id = #{user.id}
HAVING SUM(connections.value) > 0
person Matthew Rudy    schedule 13.06.2011
comment
Спасибо Мэтью - это было именно то, что я искал. На самом деле, в конце концов я обнаружил, что проще полностью изменить мои модели, чтобы пользователи сначала устанавливали соединение между двумя другими пользователями, а затем голосовали за это соединение. Не так элегантно, как ваше решение, но оно работает для моих целей. - person jonic; 14.06.2011
comment
Да, я должен был предложить вам создать отдельную модель, чтобы обналичить эти счета. В противном случае он будет работать медленно с любым большим набором данных. Вы также можете рассмотреть Mongo, так как это упрощает выполнение некоторых из этих задач. Посетите github.com/vinova/voteable_mongo, потому что вы можете использовать похожие идеи для этого - person Matthew Rudy; 15.06.2011