-
Notifications
You must be signed in to change notification settings - Fork 897
Setting whodunnit in the rails console
This page describes ways of setting whodunnit
for use in the rails console or other rails commands / rake tasks (like rake db:migrate
).
In a console session you can manually set who is responsible like this:
PaperTrail.request.whodunnit = 'Andy Stewart'
widget.update :name => 'Wibble'
widget.versions.last.whodunnit # Andy Stewart
You can avoid having to do this manually by setting your initializer to pick up the username of the current user from the OS, like this:
# config/initializers/paper_trail.rb
# the following line is required for PaperTrail >= 4.0.0 and < 12.0.0 with Rails
PaperTrail::Rails::Engine.eager_load!
# Defer evaluation in case we're using spring loader (otherwise it would be something like "spring app | app | started 13 secs ago | development")
PaperTrail.request.whodunnit = ->() {
if Rails.const_defined?('Console') || File.basename($PROGRAM_NAME) == 'rake'
"#{`whoami`.strip}: console"
else
"#{`whoami`.strip}: #{File.basename($PROGRAM_NAME)} #{ARGV.join ' '}"
end
}
You can also force every console user to type enter their name:
Rails.application.configure do
console do
puts 'Welcome'
name = nil
until name.present? do
puts 'Who are you?'
name = gets
puts 'Mmmm?' unless name.present?
end
puts "Hi #{name}"
PaperTrail.request.whodunnit = "#{name.chomp} - from console"
end
end
Being prompted for a name every time can be annoying if you frequently use the console to just run read-only queries. We only really need to know who you are if you update any records. Here's a variation that only asks for your name at the moment the first record change occurs ...
# config/initializers/console.rb
Rails.application.configure do
console do
PaperTrail.request.whodunnit = ->() {
@paper_trail_whodunnit ||= (
name = nil
until name.present? do
print "What is your name (used by PaperTrail to record who changed records)? "
name = gets.chomp
end
puts "Thank you, #{name}! Have a wonderful time!"
name
)
}
end
end
If you want to reserve the whodunnit
field for only storing the actual name or id of the human who made the change but still want to record which command and which source location the change was made from, you can add some fields:
class VersionsAddSourceLocation < ActiveRecord::Migration[5.1]
def change
change_table :versions do |t|
t.text :source_location
t.text :command
end
end
end
and do something like this in an initializer:
# config/initializers/paper_trail.rb
# Store some metadata about where the change came from, even for rake tasks, etc.
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
# 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
nil
}
Rails.application.configure do
console do
PaperTrail.request.controller_info = { command: "rails console" }
PaperTrail.request.whodunnit = ->() {
PaperTrail.set_global_metadata
@paper_trail_whodunnit ||= (
name = nil
until name.present? do
print "What is your name (used by PaperTrail to record who changed records)? "
name = gets.chomp
end
puts "Thank you, #{name}! Have a wonderful time!"
name
)
}
end
end