#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 поможет вам:
- отследите, какая команда вызывает изменения
nil
whodunnit. - Убедитесь, что вы правильно записываете изменения, инициированные задачей 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
.