/diffit

Primary LanguageRubyMIT LicenseMIT

Diffit

Зачем он нужен?

Для нескольких типов задач необходимо иметь возможность получать последние изменения определенных данных. Например при реализации offline-first концепции нужно реплицировать данные между сервером и клиентом: есть несколько клиентов, они постоянно опрашивают/подключены через веб-сокет сервер на предмет изменений. Чтобы не слать каждый раз целиком все данные, нужно иметь возможность получить все изменения с последнего таймстемпа актуального для клиента. То есть:

  1. Клиент запросил индекс, получил список данных и таймстемп когда он их получил
  2. Клиент опрашивает - не изменилось ли чего на сервере
  3. Сервер проверяет все изменения по заданному скопу начиная с запрашиваемого клиентом таймстемпа
  4. Если что-то изменилось - он отсылает клиенту только те поля записей, которые изменились в формате json.

Что он делает?

Diffit позволяет отслеживать такие изменения и генерирует из них ответ, содержащий только изменившиеся поля: В настоящее время поддерживается только json:

{
  "timestamp": "2015-05-27 21:31:45 +0300",
  "changes":
    [
      {
        "model": "ModelName",
        "record_id": 12,
        "values": {
          "column_name1": "new value",
          "column_name2": "facebook",
        },
      },
      {...}
    ]
}

Как настроить?

  1. Добавть гем в Gemfile:
gem 'diffit'
  1. Создать миграцию для внутренних нужд Diffit (инициалайзер, таблица, функция в БД, индексы, правила):
rails generate diffit:install <имя таблицы, default: "diffit">

Инициалайзер config/initializers/diffit.rb:

Diffit.setup do |config|
  config.table_name = "diffits" # название таблицы с дифами
  config.serializer = :json # сериалайзер ответа
  config.timestamp_format = ->(timestamp) { timestamp.to_s } # формат возвращаемого таймстемпа
end
  1. Создаст миграцию с триггером на таблицу, которую хотим отслеживать:
rails generate diffit:table <таблица/модель>
  1. Добавить diffit! в отслеживаемую модель:
class User < ActiveRecord::Base
  diffit!
end

Как использовать?

User.where(login: 'Vlad').diff_from(1.day.ago)
# or
Diffit.diff_from(1.day.ago, resources: [User.all, Post.where(user_id: 1), Comments.last(10)])
# or
User.first.diff_from(1.day.ago)

Тестирование

bundle
rake db:migrate
rake