Papertrail: записи с нулевыми значениями whodunnit и object_changes в журналах

#ruby-on-rails #ruby #ruby-on-rails-6 #paper-trail-gem #ruby-2.6

#ruby-на-рельсах #рубиновый #ruby-on-rails-6 #бумажный след-драгоценный камень #рубин-2.6

Вопрос:

Я настроил papertrail только на запись изменений, содержащих значение whodunnit / когда администратор вносит изменения, используя приведенное ниже условие в моей модели:

 has_paper_trail if: proc { |model| PaperTrail.request.whodunnit.present? }
 

Однако я заметил, что все еще сохраняется приличное количество записей с пустыми значениями whodunnit. Судя по записям, это, по-видимому, в основном действия «обновления», все из которых по какой-то причине имеют пустые изменения объекта. Я не уверен, почему значение является пустым или как оно вообще будет сохранено, учитывая вышеуказанное условие.

Я получаю значения whodunnit от warden в моем контроллере приложений с помощью:

 def user_for_paper_trail
  request.env['warden']amp;.user(:admin)amp;.id
end
 

Кто-нибудь сталкивался с подобным поведением раньше?

Комментарии:

1. В каком объекте вы храните whodunnit ?

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

3. Также я хотел бы, чтобы вы знали, используете ли вы info_for_paper_trail в каком-либо из своих контроллеров или вручную устанавливаете значение PaperTrail.request.controller_info . Если вы включаете whodunnit ключ в любой из них, он потенциально может переопределять значение.

4. Может ли быть так, что обновления с пустым whodunnit значением были выполнены чем-то другим, кроме контроллера, например, в фоновом задании или через консоль? Там вам нужно будет установить whodunnit значение вручную (см. Здесь: github.com/paper-trail-gem/paper_trail/wiki /… ).

5. Похоже, у вас есть записи, обновляемые в фоновом задании или вручную в консоли, вне запроса контроллера. Вы можете обновить Papertrail.whodunnit , чтобы сохранить, откуда поступает команда, если вы действительно застряли.

Ответ №1:

Добавление source_location command поля и в таблицу версий papertrail поможет вам:

  1. отследите, какая команда вызывает изменения nil whodunnit.
  2. Убедитесь, что вы правильно записываете изменения, инициированные задачей rake или консолью rails.

Для этого создайте миграцию, чтобы добавить поля source_location и command в таблицу версий:

 
class AddSourceLocationAndCommandToVersions < ActiveRecord::Migration
  def change
    add_column :versions, :source_location, :text
    add_column :versions, :command, :text
  end
end

 

У меня есть следующая настройка в моем papertrail.rb . Я использую JSON serializer , но эти изменения могут работать с обычным сериализатором. Код после serializer объявления — это то, что вас интересует:

 require "paper_trail/frameworks/rails"
require "paper_trail"

# the following line is required for PaperTrail >= 4.0.0 with Rails
PaperTrail::Rails::Engine.eager_load!

PaperTrail.config.enabled = true
PaperTrail.serializer = PaperTrail::Serializers::JSON

# Store some metadata about where the change came from, even for rake tasks, etc.
# See: https://github.com/paper-trail-gem/paper_trail/wiki/Setting-whodunnit-in-the-rails-console
def PaperTrail.set_global_metadata
  request.controller_info ||= {}
  request.controller_info[:command] ||= "#{File.basename($PROGRAM_NAME)} #{ARGV.join ' '} (#{$PID})"
  request.controller_info[:source_location] = caller.find { |line|
    line.starts_with? Rails.root.to_s and
   !line.starts_with? __FILE__
  }
end

# Defer evaluation in case we're using spring loader (otherwise it would be something like "spring app    | app | started 13 secs ago | development")
# There's no way to set up deferred evaluation of PaperTrail.request.controller_info from here like
# we can with whodunnit, so abuse that property of PaperTrail.request.whodunnit to set other
# metadata. Reserve the whodunnit field for storing the actual name or id of the human who made the
# change.
PaperTrail.request.whodunnit = ->() {
  PaperTrail.set_global_metadata
  if Rails.const_defined?("Console") || $rails_rake_task
    "#{`whoami`.strip}: console"
  else
    "#{`whoami`.strip}: #{File.basename($PROGRAM_NAME)} #{ARGV.join ' '}"
  end
}

Rails.application.configure do
  console do
    PaperTrail.request.controller_info = { command: "rails console" }
    PaperTrail.request.whodunnit = ->() {
      PaperTrail.set_global_metadata

      @paper_trail_whodunnit ||= (
        if Rails.const_defined?("Console") || $rails_rake_task
          "#{`whoami`.strip}: console"
        else
          "#{`whoami`.strip}: #{File.basename($PROGRAM_NAME)} #{ARGV.join ' '}"
        end
      )
    }
  end
end
 

Обратите внимание, что в любом месте, где создание записи происходит вне запроса, вы можете вручную присвоить whodunnit значение чему-то определенному, если вы не хотите, чтобы оно было пустым. Например. в моем начальном файле я делаю следующее:

 
class SeedCreator
  def initialize
    PaperTrail.request.whodunnit = ->() {
      PaperTrail.set_global_metadata # save source_location amp; command
      "seed" # set whodunnit value to "seed"
    }
    create_campaign
    create_users
    # more seeding of models....
  end
end

 

В дополнение к улучшению качества вашей таблицы Papertrail (зная, какая команда вызвала обновление записи), эта конфигурация должна помочь вам определить, где сохраняются фантомы whodunnits .