Fivell, मैं सिर्फ इस सवाल को देखा और इस शाम परिवर्तन ऊपर काम करने के लिए इससे पहले कि इनाम की समय सीमा समाप्त समय नहीं है, तो मैं दे देंगे आप मेरे ऑडिटिंग कोड जो ActiveRecord के साथ काम करते हैं और ActiveResource के साथ काम करना चाहिए, शायद कुछ tweaks के साथ (मैं अक्सर एआरएस का उपयोग करने के लिए पर्याप्त नहीं है)। मुझे पता है कि हमारे द्वारा उपयोग किए जाने वाले कॉलबैक हैं, लेकिन मुझे यकीन नहीं है कि अगर एआरएस में ActiveRecord की गंदे विशेषता changes
ट्रैकिंग है।
यह कोड जेएसओएन के रूप में संग्रहीत परिवर्तनों के साथ सभी मॉडलों (ऑडिट लॉग मॉडल और आपके द्वारा निर्दिष्ट किसी भी अन्य अपवादों को छोड़कर) पर प्रत्येक CREATE/UPDATE/DELETE लॉग करता है। एक साफ बैकट्रैक भी संग्रहीत किया जाता है ताकि आप यह निर्धारित कर सकें कि किस कोड ने परिवर्तन किया है (यह आपके एमवीसी के साथ-साथ रेक कार्य और कंसोल उपयोग में किसी भी बिंदु को कैप्चर करता है)।
यह कोड कंसोल उपयोग, रेक कार्य, और http अनुरोधों के लिए काम करता है, हालांकि आमतौर पर केवल अंतिम उपयोगकर्ता वर्तमान उपयोगकर्ता को लॉग करता है। (अगर मुझे सही याद है, तो ActiveRecord पर्यवेक्षक जो इसे प्रतिस्थापित करता है, रेक रेक या कंसोल में काम नहीं करता है।) ओह, यह कोड रेल 2.3 ऐप से आता है - मेरे पास कुछ रेल 3 ऐप्स हैं, लेकिन मुझे इस तरह की आवश्यकता नहीं है अभी तक उनके लिए लेखा परीक्षा का।
मेरे पास ऐसा कोड नहीं है जो इस जानकारी का एक अच्छा प्रदर्शन बनाता है (जब हमें किसी समस्या को देखने की आवश्यकता होती है तो हम केवल डेटा में खोदते हैं), लेकिन चूंकि जेएसओएन के रूप में परिवर्तनों को संग्रहीत किया जाता है, यह काफी सरल होना चाहिए।
Class User < ActiveRecord::Base
cattr_accessor :current
...
end
वर्तमान उपयोगकर्ता (ताकि तरह प्रत्येक अनुरोध के लिए आवेदन नियंत्रक में स्थापित है और ऐसा नहीं करता है:
सबसे पहले, हम User.current वर्तमान उपयोगकर्ता तो यह हर जगह उपलब्ध है, app/models/user.rb
में तो स्टोर संगामिति समस्याओं का कारण):
def current_user
User.current = session[:user_id] ? User.find_by_id(session[:user_id]) : nil
end
आप अपने रेक कार्यों में User.current
सेट कर सकते हैं अगर यह समझ बना दिया।
# == Schema Information
#
# Table name: audit_log_entries
#
# id :integer not null, primary key
# class_name :string(255)
# entity_id :integer
# user_id :integer
# action :string(255)
# data :text
# call_chain :text
# created_at :datetime
# updated_at :datetime
#
class AuditLogEntry < ActiveRecord::Base
IgnoreClassesRegEx = /^ActiveRecord::Acts::Versioned|ActiveRecord.*::Session|Session|Sequence|SchemaMigration|CronRun|CronRunMessage|FontMetric$/
belongs_to :user
def entity (reload = false)
@entity = nil if reload
begin
@entity ||= Kernel.const_get(class_name).find_by_id(entity_id)
rescue
nil
end
end
def call_chain
return if call_chain_before_type_cast.blank?
if call_chain_before_type_cast.instance_of?(Array)
call_chain_before_type_cast
else
JSON.parse(call_chain_before_type_cast)
end
end
def data
return if data_before_type_cast.blank?
if data_before_type_cast.instance_of?(Hash)
data_before_type_cast
else
JSON.parse(data_before_type_cast)
end
end
def self.debug_entity(class_name, entity_id)
require 'fastercsv'
FasterCSV.generate do |csv|
csv << %w[class_name entity_id date action first_name last_name data]
find_all_by_class_name_and_entity_id(class_name, entity_id,
:order => 'created_at').each do |a|
csv << [a.class_name, a.entity_id, a.created_at, a.action,
(a.user && a.user.first_name), (a.user && a.user.last_name), a.data]
end
end
end
end
अगला हम करने के लिए ActiveRecord::Base
करने के लिए कुछ तरीके जोड़: -
इसके बाद, हम लेखा परीक्षा की जानकारी app/models/audit_log_entry.rb
स्टोर करने के लिए मॉडल को परिभाषित आप अनुकूलित करने के लिए IgnoreClassesRegEx
किसी भी मॉडल आप लेखा परीक्षित नहीं करना चाहती फिट करने के लिए चाहता हूँ लेखा परीक्षा काम करते हैं। आप audit_log_clean_backtrace
विधि को देखना और अपनी आवश्यकताओं के लिए संशोधित करना चाहते हैं।(। Fwiw, हम अतिरिक्त मौजूदा वर्गों के लिए lib/extensions/*.rb
जो एक प्रारंभकर्ता में लोड किए गए हैं में डाल) lib/extensions/active_record.rb
में: अंत में
class ActiveRecord::Base
cattr_accessor :audit_log_backtrace_cleaner
after_create :audit_log_on_create
before_update :save_audit_log_update_diff
after_update :audit_log_on_update
after_destroy :audit_log_on_destroy
def audit_log_on_create
return if self.class.name =~ /AuditLogEntry/
return if self.class.name =~ AuditLogEntry::IgnoreClassesRegEx
audit_log_create 'CREATE', self, caller
end
def save_audit_log_update_diff
@audit_log_update_diff = changes.reject{ |k,v| 'updated_at' == k }
end
def audit_log_on_update
return if self.class.name =~ AuditLogEntry::IgnoreClassesRegEx
return if @audit_log_update_diff.empty?
audit_log_create 'UPDATE', @audit_log_update_diff, caller
end
def audit_log_on_destroy
return if self.class.name =~ AuditLogEntry::IgnoreClassesRegEx
audit_log_create 'DESTROY', self, caller
end
def audit_log_create (action, data, call_chain)
AuditLogEntry.create :user => User.current,
:action => action,
:class_name => self.class.name,
:entity_id => id,
:data => data.to_json,
:call_chain => audit_log_clean_backtrace(call_chain).to_json
end
def audit_log_clean_backtrace (backtrace)
if !ActiveRecord::Base.audit_log_backtrace_cleaner
ActiveRecord::Base.audit_log_backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
ActiveRecord::Base.audit_log_backtrace_cleaner.add_silencer { |line| line =~ /\/lib\/rake\.rb/ }
ActiveRecord::Base.audit_log_backtrace_cleaner.add_silencer { |line| line =~ /\/bin\/rake/ }
ActiveRecord::Base.audit_log_backtrace_cleaner.add_silencer { |line| line =~ /\/lib\/(action_controller|active_(support|record)|hoptoad_notifier|phusion_passenger|rack|ruby|sass)\// }
ActiveRecord::Base.audit_log_backtrace_cleaner.add_filter { |line| line.gsub(RAILS_ROOT, '') }
end
ActiveRecord::Base.audit_log_backtrace_cleaner.clean backtrace
end
end
, यहाँ परीक्षण हम इस पर कर रहे हैं - आप वास्तविक परीक्षा कार्यों को संशोधित करना होगा बेशक। test/integration/audit_log_test.rb
require File.dirname(__FILE__) + '/../test_helper'
class AuditLogTest < ActionController::IntegrationTest
def setup
end
def test_audit_log
u = users(:manager)
log_in u
a = Alert.first :order => 'id DESC'
visit 'alerts/new'
fill_in 'alert_note'
click_button 'Send Alert'
a = Alert.first :order => 'id DESC', :conditions => ['id > ?', a ? a.id : 0]
ale = AuditLogEntry.first :conditions => {:class_name => 'Alert', :entity_id => a.id }
assert_equal 'Alert', ale.class_name
assert_equal 'CREATE', ale.action
end
private
def log_in (user, password = 'test', initial_url = home_path)
visit initial_url
assert_contain 'I forgot my password'
fill_in 'email', :with => user.email
fill_in 'password', :with => password
click_button 'Log In'
end
def log_out
visit logout_path
assert_contain 'I forgot my password'
end
end
और test/unit/audit_log_entry_test.rb
:
# == Schema Information
#
# Table name: audit_log_entries
#
# id :integer not null, primary key
# class_name :string(255)
# action :string(255)
# data :text
# user_id :integer
# created_at :datetime
# updated_at :datetime
# entity_id :integer
# call_chain :text
#
require File.dirname(__FILE__) + '/../test_helper'
class AuditLogEntryTest < ActiveSupport::TestCase
test 'should handle create update and delete' do
record = Alert.new :note => 'Test Alert'
assert_difference 'Alert.count' do
assert_difference 'AuditLogEntry.count' do
record.save
ale = AuditLogEntry.first :order => 'created_at DESC'
assert ale
assert_equal 'CREATE', ale.action, 'AuditLogEntry.action should be CREATE'
assert_equal record.class.name, ale.class_name, 'AuditLogEntry.class_name should match record.class.name'
assert_equal record.id, ale.entity_id, 'AuditLogEntry.entity_id should match record.id'
end
end
assert_difference 'AuditLogEntry.count' do
record.update_attribute 'note', 'Test Update'
ale = AuditLogEntry.first :order => 'created_at DESC'
expected_data = {'note' => ['Test Alert', 'Test Update']}
assert ale
assert_equal 'UPDATE', ale.action, 'AuditLogEntry.action should be UPDATE'
assert_equal expected_data, ale.data
assert_equal record.class.name, ale.class_name, 'AuditLogEntry.class_name should match record.class.name'
assert_equal record.id, ale.entity_id, 'AuditLogEntry.entity_id should match record.id'
end
assert_difference 'AuditLogEntry.count' do
record.destroy
ale = AuditLogEntry.first :order => 'created_at DESC'
assert ale
assert_equal 'DESTROY', ale.action, 'AuditLogEntry.action should be CREATE'
assert_equal record.class.name, ale.class_name, 'AuditLogEntry.class_name should match record.class.name'
assert_equal record.id, ale.entity_id, 'AuditLogEntry.entity_id should match record.id'
assert_nil Alert.find_by_id(record.id), 'Alert should be deleted'
end
end
test 'should not log AuditLogEntry create entry and block on update and delete' do
record = Alert.new :note => 'Test Alert'
assert_difference 'Alert.count' do
assert_difference 'AuditLogEntry.count' do
record.save
end
end
ale = AuditLogEntry.first :order => 'created_at DESC'
assert_equal 'CREATE', ale.action, 'AuditLogEntry.action should be CREATE'
assert_equal record.class.name, ale.class_name, 'AuditLogEntry.class_name should match record.class.name'
assert_equal record.id, ale.entity_id, 'AuditLogEntry.entity_id should match record.id'
assert_nil AuditLogEntry.first(:conditions => { :class_name => 'AuditLogEntry', :entity_id => ale.id })
if ale.user_id.nil?
u = User.first
else
u = User.first :conditions => ['id != ?', ale.user_id]
end
ale.user_id = u.id
assert !ale.save
assert !ale.destroy
end
end
आप ही डेटा या बदलने या स्कीमा के बदलते मतलब है: यह लिंक है जिसे आप मदद कर सकता है है? ये दो अलग-अलग चीजें हैं। मेरा जवाब डेटा के लिए लक्षित है ... – lzap
डेटा बदल रहा है, स्कीमा – Fivell