Проверьте, если пользователь онлайн в режиме реального времени

Я хочу проверить, подключен ли пользователь в данный момент. Это должно быть показано в профиле пользователя.

Я получил это в моем application_controller

after_filter :user_activity

private

  def user_activity
    current_user.try :touch
  end

Я определил это в user-model

def online?
 updated_at > 10.minutes.ago
end

Я могу проверить в представлении, если пользователь онлайн: (HAML)

- if @user.online?

Это работает, но всегда требуется перезагрузить страницу, чтобы обновить эту информацию. Как это можно сделать в режиме реального времени? Может быть, с помощью ActionCable?

PS: используя devise

3 ответа

Да, Action Cable может быть использован для этого. Руководство по Rails имеет (половину) пример этого здесь: Обзор Action Cable - 6.1 Пример 1: Внешний вид пользователя

По сути, вы создаете AppearanceChannel и каждый пользователь подписан на него. Подписка на звонки appear функция для current_userкоторый затем может быть передан (например, чтобы показать онлайн-статус другим пользователям), как правило, с помощью фонового задания, такого как BroadcastAppearanceJob, (Я только начал работать через это сам).

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

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

Рассмотрите возможность использования веб-сокетов для достижения этой цели, будь то JavaScript, Obj-C/Swift или Java.

Я попытался с примером Action Cable, но у меня были некоторые проблемы (.disappear не вызывается, когда я перезагружаю сервер, также трудно обрабатывать, когда пользователь открывает несколько вкладок и т.д....)

Таким образом, простейшим рабочим решением будет способ вызывать сервер каждые 5 минут, например, в javascript:

setInterval(function(){
  var xhttp = new XMLHttpRequest();
  xhttp.open("GET", "/i_am_still_here", true);
  xhttp.send();
}, 5*60*1000);

и так в контроллере

def i_am_still_here
  current_user.update(last_seen_at:DateTime.now)
end

и так в User.rb

def is_online?
  last_seen_at > 5.minutes.ago
end

Да, как написал Ноа, для этого естественным выбором является клиентская сторона. Клиент может через выбранный интервал инициировать обновление базы данных, указывая, что они присутствуют. Обнаружение присутствия другого пользователя включает проверку того, достаточно ли свежее их обновление.

Загрузка страницы кажется обязательной, но с помощью ajax она не использует много ресурсов. Вы можете (и должны) даже создать специальный макет для целевой страницы ajax без дополнительной нагрузки, такой как css и js.

Я использую этот javascript в представлении (зависимость: jquery):

function update_presence() {
  $.ajax({
    url:  '/presence',
    // data: { "my_get_param": "whatever" },
    type: 'GET'
    })
    .done(function(response){
      $('div#last-seen').html(response);
    })
}
// run it every 30 seconds
setInterval(update_presence, 30000)

Затем определите маршрут, действие и вид, как обычно. В моемpresence действие в контроллере у меня есть вызов вспомогательной функции:

update_presence(current_user)

Вспомогательная функция - это единственная строка:

def update_presence(user)
  user.update_attribute(:last_seen, DateTime.now)
end

В представлении вы можете отобразить результат, который вам может понадобиться. Мой javascript (см. Выше) отображает результат на странице, но это только для тестирования.

<%= current_user.last_seen %>

В модели у меня есть способ проверить наличие:

def is_present?
  self.last_seen  > 2.minutes.ago
end

Так что любому пользователю вы можете позвонить @user.is_present?. Но для динамического обновления индикаторов присутствия на веб-странице, я думаю, необходим еще один вызов ajax.

Другие вопросы по тегам