<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -37,6 +37,12 @@ To get auditing outside of Rails you can explicitly declare &lt;tt&gt;acts_as_audited&lt;
       acts_as_audited :except =&gt; [:password, :mistress]
     end
 
+To record a user in the audits when the sweepers are not available, you can use &lt;tt&gt;as_user&lt;/tt&gt;:
+
+    Audit.as_user( user ) do
+      # Perform changes on audited models
+    end
+
 See http://opensoul.org/2006/07/21/acts_as_audited for more information.
 
 == Caveats</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
 # Copyright (c) 2006 Brandon Keepers
-# 
+#
 # Permission is hereby granted, free of charge, to any person obtaining
 # a copy of this software and associated documentation files (the
 # &quot;Software&quot;), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
 # distribute, sublicense, and/or sell copies of the Software, and to
 # permit persons to whom the Software is furnished to do so, subject to
 # the following conditions:
-# 
+#
 # The above copyright notice and this permission notice shall be
 # included in all copies or substantial portions of the Software.
-# 
+#
 # THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND,
 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -43,8 +43,8 @@ module CollectiveIdea #:nodoc:
         #
         # * +only+ - Only audit the given attributes
         # * +except+ - Excludes fields from being saved in the audit log.
-        #   By default, acts_as_audited will audit all but these fields: 
-        # 
+        #   By default, acts_as_audited will audit all but these fields:
+        #
         #     [self.primary_key, inheritance_column, 'lock_version', 'created_at', 'updated_at']
         #   You can add to those by passing one or an array of fields to skip.
         #
@@ -60,16 +60,16 @@ module CollectiveIdea #:nodoc:
         #       acts_as_audited :protect =&gt; false
         #       attr_accessible :name
         #     end
-        # 
+        #
         def acts_as_audited(options = {})
           # don't allow multiple calls
           return if self.included_modules.include?(CollectiveIdea::Acts::Audited::InstanceMethods)
-          
+
           options = {:protect =&gt; accessible_attributes.nil?}.merge(options)
 
           class_inheritable_reader :non_audited_columns
           class_inheritable_reader :auditing_enabled
-          
+
           if options[:only]
             except = self.column_names - options[:only].flatten.map(&amp;:to_s)
           else
@@ -81,27 +81,27 @@ module CollectiveIdea #:nodoc:
           has_many :audits, :as =&gt; :auditable, :order =&gt; &quot;#{Audit.quoted_table_name}.version&quot;
           attr_protected :audit_ids if options[:protect]
           Audit.audited_class_names &lt;&lt; self.to_s
-          
+
           after_create :audit_create_callback
           before_update :audit_update_callback
           after_destroy :audit_destroy_callback
-          
+
           attr_accessor :version
 
           extend CollectiveIdea::Acts::Audited::SingletonMethods
           include CollectiveIdea::Acts::Audited::InstanceMethods
-          
+
           write_inheritable_attribute :auditing_enabled, true
         end
       end
-    
+
       module InstanceMethods
-        
+
         # Temporarily turns off auditing while saving.
         def save_without_auditing
           without_auditing { save }
         end
-      
+
         # Executes the block with the auditing callbacks disabled.
         #
         #   @foo.without_auditing do
@@ -111,7 +111,7 @@ module CollectiveIdea #:nodoc:
         def without_auditing(&amp;block)
           self.class.without_auditing(&amp;block)
         end
-        
+
         # Gets an array of the revisions available
         #
         #   user.revisions.each do |revision|
@@ -125,28 +125,28 @@ module CollectiveIdea #:nodoc:
           revision = self.audits.find_by_version(from_version).revision
           Audit.reconstruct_attributes(audits) {|attrs| revision.revision_with(attrs) }
         end
-        
+
         # Get a specific revision specified by the version number, or +:previous+
         def revision(version)
           revision_with Audit.reconstruct_attributes(audits_to(version))
         end
-        
+
         def revision_at(date_or_time)
           audits = self.audits.find(:all, :conditions =&gt; [&quot;created_at &lt;= ?&quot;, date_or_time])
           revision_with Audit.reconstruct_attributes(audits) unless audits.empty?
         end
-        
+
         def audited_attributes
           attributes.except(*non_audited_columns)
         end
-        
+
       protected
-        
+
         def revision_with(attributes)
           returning self.dup do |revision|
             revision.send :instance_variable_set, '@attributes', self.attributes_before_type_cast
             revision.attributes = attributes.reject {|attr,_| !respond_to?(&quot;#{attr}=&quot;) }
-          
+
             # Remove any association proxies so that they will be recreated
             # and reference the correct object for this revision. The only way
             # to determine if an instance variable is a proxy object is to
@@ -160,16 +160,16 @@ module CollectiveIdea #:nodoc:
             end
           end
         end
-        
+
       private
-        
+
         def audited_changes
           changed_attributes.except(*non_audited_columns).inject({}) do |changes,(attr, old_value)|
             changes[attr] = [old_value, self[attr]]
             changes
           end
         end
-        
+
         def audits_to(version = nil)
           if version == :previous
             version = if self.version
@@ -182,7 +182,7 @@ module CollectiveIdea #:nodoc:
           end
           audits.find(:all, :conditions =&gt; ['version &lt;= ?', version])
         end
-        
+
         def audit_create(user = nil)
           write_audit(:action =&gt; 'create', :changes =&gt; audited_attributes, :user =&gt; user)
         end
@@ -196,20 +196,20 @@ module CollectiveIdea #:nodoc:
         def audit_destroy(user = nil)
           write_audit(:action =&gt; 'destroy', :user =&gt; user, :changes =&gt; audited_attributes)
         end
-      
+
         def write_audit(attrs)
           self.audits.create attrs if auditing_enabled
         end
 
-        CALLBACKS.each do |attr_name| 
+        CALLBACKS.each do |attr_name|
           alias_method &quot;#{attr_name}_callback&quot;.to_sym, attr_name
         end
-        
+
         def empty_callback #:nodoc:
         end
 
       end # InstanceMethods
-      
+
       module SingletonMethods
         # Returns an array of columns that are audited.  See non_audited_columns
         def audited_columns
@@ -227,15 +227,15 @@ module CollectiveIdea #:nodoc:
           disable_auditing
           returning(block.call) { enable_auditing if auditing_was_enabled }
         end
-        
+
         def disable_auditing
           write_inheritable_attribute :auditing_enabled, false
         end
-        
+
         def enable_auditing
           write_inheritable_attribute :auditing_enabled, true
         end
-        
+
         def disable_auditing_callbacks
           class_eval do
             CALLBACKS.each do |attr_name|
@@ -243,15 +243,22 @@ module CollectiveIdea #:nodoc:
             end
           end
         end
-        
+
         def enable_auditing_callbacks
-          class_eval do 
+          class_eval do
             CALLBACKS.each do |attr_name|
               alias_method &quot;#{attr_name}_callback&quot;.to_sym, attr_name
             end
           end
         end
-        
+
+        # All audit operations during the block are recorded as being
+        # made by +user+. This is not model specific, the method is a
+        # convenience wrapper around #Audit.as_user.
+        def audit_as( user, &amp;block )
+          Audit.as_user( user, &amp;block )
+        end
+
       end
     end
   end</diff>
      <filename>lib/acts_as_audited.rb</filename>
    </modified>
    <modified>
      <diff>@@ -11,18 +11,32 @@ require 'set'
 class Audit &lt; ActiveRecord::Base
   belongs_to :auditable, :polymorphic =&gt; true
   belongs_to :user, :polymorphic =&gt; true
-  
-  before_create :set_version_number
-  
+
+  before_create :set_version_number, :set_audit_user
+
   serialize :changes
-  
+
   cattr_accessor :audited_class_names
   self.audited_class_names = Set.new
 
   def self.audited_classes
     self.audited_class_names.map(&amp;:constantize)
   end
-  
+
+  cattr_accessor :audit_as_user
+  self.audit_as_user = nil
+
+  # All audits made during the block called will be recorded as made
+  # by +user+. This method is hopefully threadsafe, making it ideal
+  # for background operations that require audit information.
+  def self.as_user(user, &amp;block)
+    Thread.current[:acts_as_audited_user] = user
+
+    yield
+
+    Thread.current[:acts_as_audited_user] = nil
+  end
+
   # Allows user to be set to either a string or an ActiveRecord object
   def user_as_string=(user) #:nodoc:
     # reset both either way
@@ -39,7 +53,7 @@ class Audit &lt; ActiveRecord::Base
   end
   alias_method :user_as_model, :user
   alias_method :user, :user_as_string
-  
+
   def revision
     attributes = self.class.reconstruct_attributes(ancestors).merge({:version =&gt; version})
     clazz = auditable_type.constantize
@@ -47,13 +61,13 @@ class Audit &lt; ActiveRecord::Base
       m.attributes = attributes
     end
   end
-  
+
   def ancestors
     self.class.find(:all, :order =&gt; 'version',
       :conditions =&gt; ['auditable_id = ? and auditable_type = ? and version &lt;= ?',
       auditable_id, auditable_type, version])
   end
-  
+
   # Returns a hash of the changed attributes with the new values
   def new_attributes
     (changes || {}).inject({}.with_indifferent_access) do |attrs,(attr,values)|
@@ -69,7 +83,7 @@ class Audit &lt; ActiveRecord::Base
       attrs
     end
   end
-  
+
   def self.reconstruct_attributes(audits)
     attributes = {}
     result = audits.collect do |audit|
@@ -78,7 +92,7 @@ class Audit &lt; ActiveRecord::Base
     end
     block_given? ? result : attributes
   end
-  
+
 private
 
   def set_version_number
@@ -89,5 +103,10 @@ private
       }) || 0
     self.version = max + 1
   end
-  
+
+  def set_audit_user
+    self.user = Thread.current[:acts_as_audited_user] if Thread.current[:acts_as_audited_user]
+    nil # prevent stopping callback chains
+  end
+
 end</diff>
      <filename>lib/acts_as_audited/audit.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 require File.expand_path(File.dirname(__FILE__) + '/test_helper')
 
 module CollectiveIdea
-  module Acts 
+  module Acts
     class AuditedTest &lt; Test::Unit::TestCase
       should &quot;include instance methods&quot; do
         User.new.should be_kind_of(CollectiveIdea::Acts::Audited::InstanceMethods)
@@ -16,7 +16,7 @@ module CollectiveIdea
           User.non_audited_columns.should include(column)
         end
       end
-      
+
       should &quot;not save non-audited columns&quot; do
         create_user.audits.first.changes.keys.any?{|col| ['created_at', 'updated_at', 'password'].include? col}.should be(false)
       end
@@ -307,14 +307,44 @@ module CollectiveIdea
           set_table_name :users
           attr_accessible :name, :username, :password # declare attr_accessible before calling aaa
           acts_as_audited
-        end  
+        end
         should &quot;not raise an error when attr_accessible is declared before acts_as_audited&quot; do
           lambda{
             AccessibleUser.new(:name =&gt; 'NO FAIL!')
           }.should_not raise_error
         end
       end
-      
+
+      context &quot;audit as&quot; do
+        setup do
+          @user = User.create :name =&gt; 'Testing'
+        end
+
+        should &quot;record user objects&quot; do
+          Company.audit_as( @user ) do
+            company = Company.create :name =&gt; 'The auditors'
+            company.name = 'The Auditors'
+            company.save
+
+            company.audits.each do |audit|
+              audit.user.should == @user
+            end
+          end
+        end
+
+        should &quot;record usernames&quot; do
+          Company.audit_as( @user.name ) do
+            company = Company.create :name =&gt; 'The auditors'
+            company.name = 'The Auditors, Inc'
+            company.save
+
+            company.audits.each do |audit|
+              audit.username.should == @user.name
+            end
+          end
+        end
+      end
+
     end
   end
-end
\ No newline at end of file
+end</diff>
      <filename>test/acts_as_audited_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -11,7 +11,7 @@ class AuditTest &lt; Test::Unit::TestCase
       @audit.user = @user
       @audit.user.should == @user
     end
-    
+
     should &quot;be able to set the user to nil&quot; do
       @audit.user_id = 1
       @audit.user_type = 'User'
@@ -24,7 +24,7 @@ class AuditTest &lt; Test::Unit::TestCase
       @audit.user_type.should == nil
       @audit.username.should == nil
     end
-    
+
     should &quot;be able to set the user to a string&quot; do
       @audit.user = 'testing'
       @audit.user.should == 'testing'
@@ -60,7 +60,7 @@ class AuditTest &lt; Test::Unit::TestCase
     revision.name.should == user.name
     revision.new_record?.should be(true)
   end
-  
+
   should &quot;set the version number on create&quot; do
     user = User.create! :name =&gt; &quot;Set Version Number&quot;
     user.audits.first.version.should == 1
@@ -70,30 +70,30 @@ class AuditTest &lt; Test::Unit::TestCase
     user.destroy
     user.audits(true).last.version.should == 3
   end
-  
+
   context &quot;reconstruct_attributes&quot; do
     should &quot;work with with old way of storing just the new value&quot; do
       audits = Audit.reconstruct_attributes([Audit.new(:changes =&gt; {'attribute' =&gt; 'value'})])
       audits['attribute'].should == 'value'
     end
   end
-  
+
   context &quot;audited_classes&quot; do
     class CustomUser &lt; ActiveRecord::Base
     end
     class CustomUserSubclass &lt; CustomUser
       acts_as_audited
     end
-    
+
     should &quot;include audited classes&quot; do
       Audit.audited_classes.should include(User)
     end
-    
+
     should &quot;include subclasses&quot; do
       Audit.audited_classes.should include(CustomUserSubclass)
     end
   end
-  
+
   context &quot;new_attributes&quot; do
     should &quot;return a hash of the new values&quot; do
       Audit.new(:changes =&gt; {:a =&gt; [1, 2], :b =&gt; [3, 4]}).new_attributes.should == {'a' =&gt; 2, 'b' =&gt; 4}
@@ -105,6 +105,58 @@ class AuditTest &lt; Test::Unit::TestCase
       Audit.new(:changes =&gt; {:a =&gt; [1, 2], :b =&gt; [3, 4]}).old_attributes.should == {'a' =&gt; 1, 'b' =&gt; 3}
     end
   end
-  
 
-end
\ No newline at end of file
+  context &quot;as_user&quot; do
+    setup do
+      @user = User.create :name =&gt; 'testing'
+    end
+
+    should &quot;record user objects&quot; do
+      Audit.as_user(@user) do
+        company = Company.create :name =&gt; 'The auditors'
+        company.name = 'The Auditors, Inc'
+        company.save
+
+        company.audits.each do |audit|
+          audit.user.should == @user
+        end
+      end
+    end
+
+    should &quot;record usernames&quot; do
+      Audit.as_user(@user.name) do
+        company = Company.create :name =&gt; 'The auditors'
+        company.name = 'The Auditors, Inc'
+        company.save
+
+        company.audits.each do |audit|
+          audit.username.should == @user.name
+        end
+      end
+    end
+
+    should &quot;be thread safe&quot; do
+      begin
+        t1 = Thread.new do
+          Audit.as_user(@user) do
+            sleep 1
+            Company.create(:name =&gt; 'The Auditors, Inc').audits.first.user.should == @user
+          end
+        end
+
+        t2 = Thread.new do
+          Audit.as_user(@user.name) do
+            Company.create(:name =&gt; 'The Competing Auditors, LLC').audits.first.username.should == @user.name
+            sleep 0.5
+          end
+        end
+
+        t1.join
+        t2.join
+      rescue ActiveRecord::StatementInvalid
+        STDERR.puts &quot;Thread safety tests cannot be run with SQLite&quot;
+      end
+    end
+  end
+
+end</diff>
      <filename>test/audit_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -16,6 +16,6 @@ postgresql:
 mysql:
   :adapter: mysql
   :host: localhost
-  :username: rails
+  :username: root
   :password:
-  :database: acts_as_audited_plugin_test
\ No newline at end of file
+  :database: acts_as_audited_plugin_test</diff>
      <filename>test/db/database.yml</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>21fd3ac9719830bb1850bd5557df23a6e0926f00</id>
    </parent>
  </parents>
  <author>
    <name>Kenneth Kalmer</name>
    <email>kenneth.kalmer@gmail.com</email>
  </author>
  <url>http://github.com/collectiveidea/acts_as_audited/commit/b624ba06b7d39328be58a4ee80fb94a600e8b010</url>
  <id>b624ba06b7d39328be58a4ee80fb94a600e8b010</id>
  <committed-date>2009-06-03T06:07:37-07:00</committed-date>
  <authored-date>2009-06-03T05:19:54-07:00</authored-date>
  <message>Support for thread-safe 'background auditing'</message>
  <tree>4bd681c334b520665f10fac3e0ef9a153fed0b4e</tree>
  <committer>
    <name>Brandon Keepers</name>
    <email>brandon@collectiveidea.com</email>
  </committer>
</commit>
