Задача метода классов с двунаправленными самореференциальными ассоциациями - PullRequest
1 голос
/ 09 июня 2011

Я пытаюсь создать приложение, в котором пользователи ('current_user') оценивают совместимость между двумя другими пользователями ('user1' и 'user2'). Они могут оценивать совместимость как положительно, так и отрицательно: оценка «совместимости» двух пользователей создает два ресурса одного и того же класса («positive_connection» и «inverse_positive_connection» - для двунаправленности), а оценка их «несовместимыми» также создает два ресурса («absolute_connection»). 'и' inverse_negative_connection '). Таким образом, существуют модели для positive_connection, absolute_connection и пользователя.

Каждый рейтинговый ресурс принадлежит как пользователю, который его создал, так и пользователям, связанным с ним. Важно иметь как положительные, так и отрицательные оценки.

Это моя проблема: на каждой странице пользователя (@user) я хочу отображать отдельные списки:

  1. пользователей, которые overall_positively_connected_to(@user) (т.е. positive_connections.count > negative_ratings.count) и

  2. пользователей, которые overall_negatively_connected_to(@user) (т.е. negative_connections.count > positive_ratings.count).


Кажется, я не могу написать метод class , который извлекает только тех пользователей, которые имеют «совместимый» или «несовместимый» рейтинг

.

После прочтения учебника Майкла Хартла по рельсам (я совершенно новичок во всем этом), я думаю, мне нужно написать что-то вроде этого в модели User:

class User < ActiveRecord::Base


def self.that_are_compatible_with

     User.overall_positively_connected_to(user)
end
.
.
.


EDIT

Начиная абсолютно без знания SQL-запросов, я написал эти два метода класса для поиска пользователей, которые отрицательно и положительно связаны с @user (соответственно):

.
.
.
  def self.with_neg_connections_to(user)
   joins(:negative_connections).
   where(:negative_connections => {:user_a_id => user})
  end

  def self.with_pos_connections_to(user)
   joins(:positive_connections).
   where(:positive_connections => {:user_a_id => user})
  end


Но это не сильно помогает. Что мне нужно, это метод, который получает пользователей overall_positively_connected_to(user). Я предполагаю, что метод будет включать в себя два соединения и что-то вроде этого:

  def self.overall_positively_connected_to(user)
    joins(:positive_connections).joins(:negative_connections).
    where((:negative_connections => {:user_a_id => user}).count > (:positive_connections => {:user_a_id => user}).count)
  end


Но здесь я полностью застрял: это явно не правильно. Я не могу найти другие примеры, как это нигде ...

Любая помощь по этому вопросу была бы великолепна, поскольку я понятия не имею, когда речь идет о SQL-запросах. Дайте мне знать, если нужно больше кода. Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 15 июня 2011

Поработав с этим в течение нескольких дней, я решил, что лучший способ решить проблему - это, вероятно, изменить раунд моделей - либо добавив дополнительную модель «соединения», а пользователи проголосуют положительно или отрицательно по каждому из них. или уменьшением до одной модели «соединения», где положительный или отрицательный символ каждого соединения отмечен знаком + 1 / -1.

Несколько вариантов можно найти в ответах на этот вопрос .

0 голосов
/ 11 июня 2011

Если я правильно понимаю проблему, одна из вещей, которая делает все это сложным, заключается в том, что целевой пользователь может быть либо User1, либо User2.То есть, если мы будем после всех подключений для пользователя с ID = 4, тогда у нас может быть User1 = 4 или User2 = 4 ... это правильно?

Если это так, тогда предположим, что ваши positive_connectionsи модели / таблицы absolute_connections имеют следующие поля:

  • ID: первичный ключ
  • ReportingUser: пользователь, устанавливающий соединение
  • UserA: первый пользователь, подключившийся
  • Пользователь B: второй пользователь для подключения

Тогда следующий (довольно грязный) SQL даст вам сводку как положительных, так и отрицательных соединений для каждого пользователя:

set @user = 2;

SELECT DISTINCT
    @user TargetUser,
    u.ID as OtherUser,
    COALESCE(qryPositive.PositiveConnections, 0) as PositiveConnections,
    COALESCE(qryNegative.NegativeConnections, 0) as NegativeConnections,
    case
      when COALESCE(qryPositive.PositiveConnections, 0) > COALESCE(qryNegative.NegativeConnections, 0)
      then 'positive'
      when COALESCE(qryPositive.PositiveConnections, 0) < COALESCE(qryNegative.NegativeConnections, 0)
      then 'negative'
      else 'neutral'
    end as Status
FROM
    users u
LEFT JOIN
    (
        -- The number of positive connections between the @user and each other user
        SELECT
            @user TargetUser,
            a.OtherUser,
            COUNT(*) as PositiveConnections
        FROM
        (
            -- The positive_connections rows with our @user in it
            -- and the other user that the connection associates them with
            select -- pc.ID as pcID, pc.UserA, pc.UserB,
            case
              when pc.UserA = @user then pc.UserB
              else pc.UserA
            end as OtherUser
            from positive_connections pc
            where
            (
              -- Check both columns
              (pc.UserA = @user)
              or
              (pc.UserB = @user)
            )
        ) a
        GROUP BY
            OtherUser
    ) qryPositive
    on qryPositive.OtherUser = u.ID

LEFT JOIN
    (
        -- The number of negative connections between the @user and each other user
        SELECT
            @user TargetUser,
            b.OtherUser,
            COUNT(*) as NegativeConnections
        FROM
        (
            -- The negative_connections rows with our @user in it
            -- and the other user that the connection associates them with
            select -- pc.ID as pcID, pc.UserA, pc.UserB,
            case
              when pc.UserA = @user then pc.UserB
              else pc.UserA
            end as OtherUser
            from negative_connections pc
            where
            (
              -- Check both columns
              (pc.UserA = @user)
              or
              (pc.UserB = @user)
            )
        ) b
        GROUP BY
            OtherUser
    ) qryNegative
    on qryNegative.OtherUser = u.ID

WHERE
    u.ID <> @user

Это касается SQL (я могу опубликовать примеры данных, которые я использовал, если хотите).Теперь, в рамках rails, было бы неплохо разделить это на отдельные методы классов в вашей модели, как вы начали это делать.

Что касается построения запросов с использованием rails, эта страница является довольно хорошейресурс.http://guides.rubyonrails.org/active_record_querying.html

Это то, что вы ищете?Если это так, то мы можем работать над созданием запросов активной записи.(У меня такое чувство, что я, возможно, неправильно понял проблему ...)

...