Search code examples
ruby-on-railsrubyacts-as-audited

Inspect who change a model rails 3


I have a Rails 3 application with a loads of models. Also i have a loads of rake tasks and more. At least i have a necessary to inspect all changes in my database. Each time when record changes i have to know which line of script made a change.

I used to use audited-gem, that's fine, but doesn't answer about initiator of changes, and that's make me sad. I'm really stuck with this.


Solution

  • We use acts_as_audited for this, it's just called "Audited" now -

    https://github.com/collectiveidea/audited

    This works fine but didn't record the user that made the change when the change was made via the console or a rake task, as you say. So, i came up with a quite hacky solution (which works fine for us, but may be system-dependent) for recording the user on our production server.

    At the company where I work, there are two rails devs. We're the only people that ever ssh onto our production server, and we have our public rsa keys stored on the server, in ~/.ssh/authorized_keys.

    When I ssh on, my key is read, and i can actually do some more things, like set environment variables. So, we both modified our keys, as stored on the server, to look like this

    #mine
    environment="railsid=1182" ssh-rsa <keystring> <computer name>
    
    #my colleague's
    environment="railsid=1" ssh-rsa <keystring> <computer name>
    

    1182 and 1 are the ids of our user records on the system. This will set an environment variable of "railsid" to either "1182" or "1", depending on which of us is logged in. (we both log in as the same user on the server - this is the user that the app runs in so it's easier for permissions etc if we both just use that)

    I then modified the code of acts_as_audited: normally it gets the current logged in user, like so:

    def set_audit_user
      if Thread.current[:acts_as_audited_user]
        self.user = Thread.current[:acts_as_audited_user] 
      end
      nil # prevent stopping callback chains
    end
    

    My change was to see, if there's no current user, if that environment variable had been set, and if so, to use that as the user for the audit record:

    def set_audit_user
      if Thread.current[:acts_as_audited_user]
        self.user = Thread.current[:acts_as_audited_user] 
      elsif ENV['railsid'] && u = User.find_by_id(ENV['railsid'])
        self.user = u
      end
      nil # prevent stopping callback chains
    end
    

    We've been using acts_as_audited for a long time - we installed it as a plugin rather than a gem, so i made this change in vendor/plugins/acts_as_audited/lib/acts_as_audited/audit.rb

    If you wanted to do this too, you'd be using the gem instead, so you'd need to make a monkey patch,eg in your lib folder. (i've got a file lib/gem_extensions.rb which i use for stuff like this).

    Like i say, this is super-hacky, but it works :)