Как я могу сгруппировать элементы в потоке вместе, если они принадлежат одному пользователю - PullRequest
1 голос
/ 04 июля 2010

У меня есть поток действий (Activity), принадлежащих пользователям и с create_at. Я хотел бы представить поток из 10 последних мероприятий, с оговоркой, что я хочу сгруппировать действия вместе. Я знаю, что могу использовать group_by, но я не хочу группировать все по пользователю, только те действия, которые появляются> 2 раза подряд.

  • Том что-то сказал
  • Джо что-то сделал
  • Джо пнул что-то
  • Джо что-то ударил
  • Джо что-то сказал
  • Билл что-то сделал
  • Билл отправил что-то

Если бы это было сгруппировано, это было бы так:

  • Том что-то сказал
  • Джо что-то сделал
  • Джо пнул что-то [Больше от Джо ...]
  • Билл что-то сделал
  • Билл что-то прислал

Где ссылка «Еще» открывает скрытый раздел.

Ответы [ 2 ]

1 голос
/ 02 августа 2012
0 голосов
/ 05 июля 2010

Я не думаю, что есть какой-то особый способ сделать это. Вы просто должны это сделать.

Допустим, вы можете эффективно захватить все действия и связанных с ними пользователей. Вы, вероятно, не можете сделать это эффективно, для чего-то столь же частого, как активность на веб-сайте, но гипотетически, скажем, вы могли бы, ради простоты.

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

Оставьте свои пороги для просмотра. (Не более 2 последовательных действий, всего не более 10 строк.)

Если в Ruby есть какой-то причудливый способ сбора последовательных элементов из массива, то я, вероятно, буду выглядеть глупо, но вот некоторый ( непроверенный ) код:

class Activity < ActiveRecord::Base
  belongs_to :user

  def self.each_consecutive_group(options={})
    default_options = { :order => 'created_at DESC' }

    current_group = nil
    last_user_id = false
    self.all(default_options.merge(options)).each do |activity|
      # Look for consecutive activities from the same user.
      # (This is never true on the first iteration.)
      if last_user_id == activity.user_id
        current_group << activity
      else
        # The nil case happens during first iteration.
        yield current_group unless current_group.nil?

        # Initialize state for the next group of activities.
        current_group = [activity]
        last_user_id = activity.user_id
      end
    end
    # Do we still have something to yield?
    yield current_group if current_group
  end

  # Just return the above as an array, rather than iterating.
  def self.consecutive_groups(options={})
    groups = []
    self.each_consecutive_group(options) { |group| groups << group }
    groups
  end
end

# Usage:
Activity.each_grouped(:include => :user, :limit => 30) do |group|
  # [...]
end

# Or if you want to pass something from the controller to the view:
@activity_groups = Activity.grouped(:include => :user, :limit => 30)

Чтобы затем уменьшить проблему с производительностью, я бы просто взял безопасный запас. Если вам нужно 10 строк, вы можете выбрать область из 20 видов деятельности для поиска, и в ней будет 10 скрытых записей. Больше, и вы можете увидеть менее 10 строк. Выбор 20 записей вряд ли много, и вы можете расширить это число.

Если вы твердо настроены на всегда с 10 строками, то вам, вероятно, придется передвинуть пороговый код в вышеприведенное любым способом. Затем вы можете использовать find_in_batches вместо :limit и продолжать цикл до тех пор, пока ваш порог не будет превышен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...