Посібник з м’якого видалення та ведення журналу аудиту в Rails

pic

Посібник по м'якому видаленню та веденню журналу аудиту в Rails

У міру того як фінансові додатки стають дедалі складнішими, цілісність даних стає критично важливою. Сьогодні я поділюсь досвідом впровадження надійної системи м'якого видалення з комплексним веденням журналу аудиту у фінансовому додатку на Rails. Давайте дослідимо, як ми можемо зберігати трасування даних, при цьому забезпечуючи, що нічого не буде втрачено назавжди.

Виклик

У фінансових додатках просто видаляти записи не можна. Ми повинні:

  • Відстежувати всі зміни фінансових записів
  • Зберігати зв'язки даних
  • Забезпечувати відновлення записів
  • Гарантувати відповідність вимогам аудиту

Реалізація м'якого видалення за допомогою actsasparanoid

Гем acts_as_paranoid забезпечує надійну основу для м'якого видалення. Ось як ми реалізували це в нашій моделі Account:

class Account < ApplicationRecord  
 acts_as_paranoid  

 belongs_to :currency, optional: true  
 belongs_to :user  
 has_many :transactions, dependent: :destroy  

 validates :name, presence: true  
 validates :balance, presence: true  
end

Ми додали стовпець deleted_at типу timestamp, який, коли він встановлений, ефективно "приховує" запис від звичайних запитів, але зберігає його в базі даних.

Розширена система ведення журналу аудиту

Ми створили комплексну систему ведення журналу аудиту, яка відстежує кожну зміну у фінансових записах:

class AuditLog < ApplicationRecord  
 acts_as_paranoid  

 belongs_to :user, optional: true  

 validates :class_name, presence: true  
end

Журнал аудиту інтегровано в нашому сервісному шарі за допомогою базового класу сервісу:

class ApplicationService  
 private  

 def log_event(user:, data: {})  
 event_data = {   
 user: user,   
 data: data,   
 class_name: self.class.to_s   
 }.compact  
 AuditLog.create(event_data)  
 end  
end

Відстеження транзакцій під час видалення

Для фінансових транзакцій ми зберігаємо повну трасу аудиту навіть після видалення. Ось як ми обробляємо видалення транзакції:

class Transactions::DestroyService < ApplicationService  
 def call  
 return failure([TRANSACTION_NOT_FOUND_MESSAGE]) unless transaction  
 return failure([USER_NOT_FOUND_MESSAGE]) unless user  

 ActiveRecord::Base.transaction do  
 transaction.destroy  
 update_account_balance  
 log_event(user: user, data: { transaction: transaction })  
 success(TRANSACTION_DELETED_MESSAGE)  
 rescue ActiveRecord::RecordInvalid => e  
 failure(e.record.errors.full_messages)  
 end  
 end  

 private  

 def update_account_balance  
 factor = transaction.transaction_type == 'expense' ? 1 : -1  
 transaction.account.update!(  
 balance: transaction.account.balance + (transaction.amount * factor)  
 )  
 end  
end

Забезпечення цілісності даних

Для забезпечення цілісності даних ми реалізували кілька ключових функцій:

  1. Атомарні транзакції: Всі пов'язані операції обгорнуті в транзакції бази даних:
ActiveRecord::Base.transaction do  
 transaction.destroy  
 update_account_balance  
 log_event(user: user, data: { transaction: transaction })  
end

2. Збереження зв'язків: Ми зберігаємо зв'язки між записами навіть після видалення:

class User < ApplicationRecord  
 acts_as_paranoid  
 has_many :audit_logs, dependent: :nullify  
 has_many :accounts, dependent: :destroy  
 has_many :transactions, dependent: :destroy  
end

3. Автоматизоване очищення: Ми обробляємо старі м'яко видалені записи за допомогою фону роботи:

class RemoveSoftDeletedUsersJob < ApplicationJob  
 def perform  
 return unless Settings.jobs.remove_soft_deleted_users.enabled  

 User.deleted_before_time(eval(Settings.jobs.remove_soft_deleted_users.time).ago)  
 .each(&:destroy_fully!)  
 end  
end

Реальні переваги

Ця реалізація принесла кілька переваг:

  1. Відповідність вимогам: Повні журнали аудиту для фінансових транзакцій
  2. Відновлення даних: Легке відновлення випадково видалених записів
    3.
    Продуктивність: Мінімальний вплив на продуктивність бази даних при збереженні цілісності даних
  3. Обслуговування: Автоматизоване очищення старих м'яко видалених записів

Результати навчання

Створення цієї системи дало мені кілька важливих уроків:

  1. Завжди враховуйте ширші наслідки видалення даних у фінансових системах
  2. Проектуйте з урахуванням можливості аудиту з самого початку
  3. Баланс між збереженням даних та продуктивністю системи
  4. Важливість атомарних операцій для збереження консистентності даних

Кращі практики

При впровадженні подібної системи варто враховувати наступні рекомендації:

  1. Завжди використовуйте транзакції бази даних для пов'язаних операцій
  2. Логуйте як саму дію, так і стан даних
  3. Реалізуйте стратегії очищення старих м'яко видалених записів
  4. Зберігайте зв'язки між пов'язаними записами навіть після їх видалення
  5. Проектуйте систему аудиту так, щоб вона була зручна для запитів і легко підтримувана

Ця реалізація виявилася надійною в умовах продуктивного середовища, обробляючи мільйони фінансових транзакцій при збереженні повної трасованості та цілісності даних. Поєднання м'якого видалення та комплексного ведення журналу аудиту забезпечує безпеку та прозорість, необхідні для фінансових додатків.

Пам'ятайте, що у фінансових додатках справа не тільки у збереженні даних — важливо також зберігати перевірену історію кожної зміни при забезпеченні цілісності даних на кожному етапі.

Щасливого кодування!

Оригінал опубліковано на https://sulmanweb.com.

Перекладено з: Rails Soft Delete & Audit Logging Guide

Leave a Reply

Your email address will not be published. Required fields are marked *