pg_audit_log 0.5.6 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8f7c84ef450326cc585d0ffdf7963a07ba9e2341
4
+ data.tar.gz: a61e2f9ab3687d5e2afb14b6542adf56767c01af
5
+ SHA512:
6
+ metadata.gz: ce57db6aee49eb73c8b0e739a6be62281f361b79ddf2290108ceb7374d86b345c0342b81e527714b71b1ed0dda6dd1b6a047b23c643e91d2efd7221a31551ea1
7
+ data.tar.gz: a2e21fefdf61ea1ec1865d020c3c4f38382e8c4f1a664c2e28b5305e198656ae522fd82f528c410c00f03a6d6f069d4ea7fd1289beff0d8490c9157a960e89f2
data/.travis.yml ADDED
@@ -0,0 +1,28 @@
1
+ language: ruby
2
+
3
+ addons:
4
+ postgresql: '9.3'
5
+
6
+ before_script:
7
+ - psql -c 'CREATE DATABASE pg_audit_log_test;' -U postgres
8
+
9
+ rvm:
10
+ - 1.9.3
11
+ - 2.0.0
12
+ - 2.1.1
13
+ #- jruby-19mode
14
+ - rbx-2.2
15
+
16
+ env:
17
+ #- RAILS_BRANCH="master"
18
+ #- RAILS_BRANCH="4-1-stable"
19
+ #- RAILS_BRANCH="4-0-stable"
20
+ - RAILS_VERSION="~> 4.1.0"
21
+ - RAILS_VERSION="~> 4.0.0"
22
+ - RAILS_VERSION="~> 3.2.0"
23
+
24
+ matrix:
25
+ allow_failures:
26
+ - env: RAILS_BRANCH="master"
27
+ - env: RAILS_BRANCH="4-1-stable"
28
+ - env: RAILS_BRANCH="4-0-stable"
data/Gemfile CHANGED
@@ -1,9 +1,7 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies the .gemspec
4
4
  gemspec
5
5
 
6
- group :development do
7
- gem 'wirble'
8
- end
9
-
6
+ gem 'rails', :github => 'rails', :branch => ENV['RAILS_RECORD_BRANCH'] if ENV['ACTIVE_RECORD_BRANCH']
7
+ gem 'rails', ENV['RAILS_VERSION'] if ENV['RAILS_RECORD_VERSION']
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-11 Case Commons, LLC
1
+ Copyright (c) 2009-2014 Case Commons, LLC
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # pg_audit_log
2
+
3
+ [![Build Status](https://secure.travis-ci.org/Casecommons/pg_audit_log.png?branch=master)](https://travis-ci.org/Casecommons/pg_audit_log)
4
+ [![Code Climate](https://codeclimate.com/github/Casecommons/pg_audit_log.png)](https://codeclimate.com/github/Casecommons/pg_audit_log)
5
+ [![Gem Version](https://badge.fury.io/rb/pg_audit_log.png)](https://rubygems.org/gems/pg_audit_log)
6
+
7
+ ## Description
8
+
9
+ PostgreSQL-only database-level audit logging of all databases changes using a completely transparent stored procedure and triggers.
10
+ Comes with specs for your project and a rake task to generate the reverse SQL to undo changes logged.
11
+
12
+ All SQL `INSERT`s, `UPDATE`s, and `DELETE`s will be captured. Record columns that do not change do not generate an audit log entry.
13
+
14
+ ## Installation
15
+
16
+ - First, enable plpgsql langauges in your postgresql instance. Execute the following as a superuser in postgres make sure your database has plpgsql enabled:
17
+
18
+ CREATE OR REPLACE PROCEDURAL LANGUAGE plpgsql;
19
+
20
+ - Generate the appropriate Rails files:
21
+
22
+ rails generate pg_audit_log:install
23
+
24
+ - Install the PostgreSQL function and triggers for your project:
25
+
26
+ rake pg_audit_log:install
27
+
28
+ ## Usage
29
+
30
+ The PgAuditLog::Entry ActiveRecord model represents a single entry in the audit log table. Each entry represents a single change to a single field of a record in a table. So if you change 3 columns of a record, that will generate 3 corresponding PgAuditLog::Entry records.
31
+
32
+ You can see the SQL it injects on every query by running with LOG_AUDIT_SQL
33
+
34
+ ### Migrations
35
+
36
+ TODO
37
+
38
+ ### schema.rb and development_structure.sql
39
+
40
+ Since schema.rb cannot represent TRIGGERs or FUNCTIONs you will need to set your environment to generate SQL instead of Ruby for your database schema and structure. In your application environment put the following:
41
+
42
+ config.active_record.schema_format = :sql
43
+
44
+ And you can generate this sql using:
45
+
46
+ rake db:structure:dump
47
+
48
+ ## Uninstalling
49
+
50
+ rake pg_audit_log:uninstall
51
+
52
+ ## Performance
53
+
54
+ On a 2.93GHz i7 with PostgreSQL 9.1 the audit log has an overhead of about 0.0035 seconds to each `INSERT`, `UPDATE`, or `DELETE`.
55
+
56
+ ## Requirements
57
+
58
+ - ActiveRecord
59
+ - PostgreSQL
60
+ - Rails 3.2
61
+
62
+ ## LICENSE
63
+
64
+ Copyright © 2010–2014 Case Commons, LLC. Licensed under the MIT license, available in the “LICENSE” file.
data/Rakefile CHANGED
@@ -1,12 +1,7 @@
1
- require 'rake'
2
- require 'rspec/core'
1
+ require 'bundler/gem_tasks'
3
2
  require 'rspec/core/rake_task'
4
3
 
5
- require 'bundler'
6
- Bundler::GemHelper.install_tasks
4
+ desc 'Run specs'
5
+ RSpec::Core::RakeTask.new
7
6
 
8
7
  task :default => :spec
9
-
10
- desc "Run all specs in spec directory (excluding plugin specs)"
11
- RSpec::Core::RakeTask.new(:spec)
12
-
data/lib/pg_audit_log.rb CHANGED
@@ -1,15 +1,16 @@
1
1
  module PgAuditLog
2
- IGNORED_TABLES = ["plugin_schema_migrations", "sessions", "schema_migrations"]
2
+ IGNORED_TABLES = [
3
+ 'plugin_schema_migrations'.freeze,
4
+ 'sessions'.freeze,
5
+ 'schema_migrations'.freeze,
6
+ ]
3
7
  end
4
8
 
5
- require "active_record"
6
- require "pg_audit_log/version"
7
-
8
- raise "ActiveRecord #{::ActiveRecord::VERSION::MAJOR}.x unsupported!" unless ::ActiveRecord::VERSION::MAJOR == 3
9
-
10
- require "pg_audit_log/extensions/postgresql_adapter.rb"
11
- require "pg_audit_log/active_record"
12
- require "pg_audit_log/entry"
13
- require "pg_audit_log/function"
14
- require "pg_audit_log/triggers"
9
+ require 'active_record'
10
+ require 'pg_audit_log/version'
15
11
 
12
+ require 'pg_audit_log/extensions/postgresql_adapter.rb'
13
+ require 'pg_audit_log/active_record'
14
+ require 'pg_audit_log/entry'
15
+ require 'pg_audit_log/function'
16
+ require 'pg_audit_log/triggers'
@@ -1,14 +1,10 @@
1
1
  class PgAuditLog::Entry < ActiveRecord::Base
2
- TABLE_NAME = "audit_log"
3
- if ::ActiveRecord::VERSION::MAJOR == 3 && ::ActiveRecord::VERSION::MINOR >= 2
4
- self.table_name = TABLE_NAME
5
- else
6
- set_table_name TABLE_NAME
7
- end
2
+ TABLE_NAME = 'audit_log'.freeze
3
+ self.table_name = TABLE_NAME
8
4
 
9
5
  class CannotDeleteError < StandardError
10
6
  def message
11
- "Audit Logs cannot be deleted!"
7
+ 'Audit Logs cannot be deleted!'
12
8
  end
13
9
  end
14
10
 
@@ -90,5 +86,4 @@ class PgAuditLog::Entry < ActiveRecord::Base
90
86
  raise CannotDeleteError
91
87
  end
92
88
  end
93
-
94
89
  end
@@ -1,16 +1,12 @@
1
- require "active_record/connection_adapters/postgresql_adapter"
1
+ require 'active_record/connection_adapters/postgresql_adapter'
2
2
 
3
3
  # Did not want to reopen the class but sending an include seemingly is not working.
4
4
  class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
5
- def drop_table_with_auditing(table_name, options = {})
5
+ def drop_table_with_auditing(table_name)
6
6
  if PgAuditLog::Triggers.tables_with_triggers.include?(table_name)
7
7
  PgAuditLog::Triggers.drop_for_table(table_name)
8
8
  end
9
- if ::ActiveRecord::VERSION::MAJOR == 3 && ::ActiveRecord::VERSION::MINOR >= 2
10
- drop_table_without_auditing(table_name)
11
- else
12
- drop_table_without_auditing(table_name, options)
13
- end
9
+ drop_table_without_auditing(table_name)
14
10
  end
15
11
  alias_method_chain :drop_table, :auditing
16
12
 
@@ -69,14 +65,12 @@ class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
69
65
  end
70
66
  alias_method_chain :execute, :pg_audit_log
71
67
 
72
- if ::ActiveRecord::VERSION::MAJOR >= 3 && ::ActiveRecord::VERSION::MINOR >= 1
73
- def exec_query_with_pg_audit_log(sql, name = 'SQL', binds = [])
74
- conn = exec_query_without_pg_audit_log(sql, name, binds)
75
- set_audit_user_id_and_name
76
- conn
77
- end
78
- alias_method_chain :exec_query, :pg_audit_log
68
+ def exec_query_with_pg_audit_log(sql, name = 'SQL', binds = [])
69
+ conn = exec_query_without_pg_audit_log(sql, name, binds)
70
+ set_audit_user_id_and_name
71
+ conn
79
72
  end
73
+ alias_method_chain :exec_query, :pg_audit_log
80
74
 
81
75
  private
82
76
 
@@ -86,5 +80,4 @@ class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
86
80
  user_unique_name = current_user.try(:unique_name) || "UNKNOWN"
87
81
  return [user_id, user_unique_name]
88
82
  end
89
-
90
83
  end
@@ -4,23 +4,23 @@ module PgAuditLog
4
4
 
5
5
  class << self
6
6
  def name
7
- "audit_changes"
7
+ 'audit_changes'
8
8
  end
9
9
 
10
10
  def users_table_name
11
- "users"
11
+ 'users'
12
12
  end
13
13
 
14
14
  def user_id_field
15
- "user_id"
15
+ 'user_id'
16
16
  end
17
17
 
18
18
  def user_name_field
19
- "user_unique_name"
19
+ 'user_unique_name'
20
20
  end
21
21
 
22
22
  def users_access_column
23
- "last_accessed_at"
23
+ 'last_accessed_at'
24
24
  end
25
25
 
26
26
  def pg_audit_log_old_style_user_id
@@ -59,11 +59,11 @@ module PgAuditLog
59
59
  unique_name varchar;
60
60
  column_name varchar;
61
61
  BEGIN
62
- user_identifier := #{pg_audit_log_old_style_user_id ? "current_setting('audit.user_id')" : 'pg_temp.pg_audit_log_user_identifier()'};
62
+ user_identifier := #{pg_audit_log_old_style_user_id ? %q(current_setting('audit.user_id')) : 'pg_temp.pg_audit_log_user_identifier()'};
63
63
  IF user_identifier = #{DISABLED_USER} THEN
64
64
  RETURN NULL;
65
65
  END IF;
66
- unique_name := #{pg_audit_log_old_style_user_id ? "current_setting('audit.user_unique_name')" : 'pg_temp.pg_audit_log_user_unique_name()'};
66
+ unique_name := #{pg_audit_log_old_style_user_id ? %q(current_setting('audit.user_unique_name')) : 'pg_temp.pg_audit_log_user_unique_name()'};
67
67
  primary_key_column := NULL;
68
68
  EXECUTE 'SELECT pg_attribute.attname
69
69
  FROM pg_index, pg_class, pg_attribute
@@ -1,6 +1,6 @@
1
1
  module PgAuditLog
2
2
  class Triggers < PgAuditLog::ActiveRecord
3
- class MissingTriggers < Exception
3
+ class MissingTriggers < StandardError
4
4
  def initialize(tables)
5
5
  @tables = tables
6
6
  end
@@ -57,12 +57,10 @@ module PgAuditLog
57
57
  end
58
58
 
59
59
  def without_triggers
60
- begin
61
- disable
62
- yield
63
- ensure
64
- enable
65
- end
60
+ disable
61
+ yield
62
+ ensure
63
+ enable
66
64
  end
67
65
 
68
66
  def create_for_table(table_name)
@@ -70,11 +68,11 @@ module PgAuditLog
70
68
  PgAuditLog::Function.install unless PgAuditLog::Function.installed?
71
69
  return if tables_with_triggers.include?(table_name)
72
70
  execute <<-SQL
73
- CREATE TRIGGER #{trigger_name_for_table(table_name)}
74
- AFTER INSERT OR UPDATE OR DELETE
75
- ON #{table_name}
76
- FOR EACH ROW
77
- EXECUTE PROCEDURE #{PgAuditLog::Function.name}()
71
+ CREATE TRIGGER #{trigger_name_for_table(table_name)}
72
+ AFTER INSERT OR UPDATE OR DELETE
73
+ ON #{table_name}
74
+ FOR EACH ROW
75
+ EXECUTE PROCEDURE #{PgAuditLog::Function.name}()
78
76
  SQL
79
77
  end
80
78
 
@@ -92,7 +90,7 @@ module PgAuditLog
92
90
  end
93
91
 
94
92
  def trigger_prefix
95
- "audit_"
93
+ 'audit_'
96
94
  end
97
95
 
98
96
  def trigger_name_for_table(table_name)
@@ -1,3 +1,3 @@
1
1
  module PgAuditLog
2
- VERSION = "0.5.6"
2
+ VERSION = '0.6.0'.freeze
3
3
  end
data/pg_audit_log.gemspec CHANGED
@@ -1,26 +1,27 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "pg_audit_log/version"
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'pg_audit_log/version'
4
4
 
5
- Gem::Specification.new do |s|
6
- s.name = "pg_audit_log"
7
- s.version = PgAuditLog::VERSION
8
- s.platform = Gem::Platform::RUBY
9
- s.authors = ["Case Commons, LLC"]
10
- s.email = ["casecommons-dev@googlegroups.com"]
11
- s.homepage = "https://github.com/Casecommons/pg_audit_log"
12
- s.summary = %q{postgresql only database-level audit logging of all databases changes}
13
- s.description = %q{A completely transparent audit logging component for your application using a stored procedure and triggers. Comes with specs for your project and a rake task to generate the reverse SQL to undo changes logged}
14
- s.post_install_message = %q{Please run PgAuditLog::Function.install (in console/migration) to install the new versions of the database functions}
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'pg_audit_log'
7
+ spec.version = PgAuditLog::VERSION
8
+ spec.authors = ['Case Commons, LLC']
9
+ spec.email = ['casecommons-dev@googlegroups.com']
10
+ spec.homepage = 'https://github.com/Casecommons/pg_audit_log'
11
+ spec.summary = %q{PostgreSQL-only database-level audit logging of all databases changes.}
12
+ spec.description = %q{A completely transparent audit logging component for your application using a stored procedure and triggers. Comes with specs for your project and a rake task to generate the reverse SQL to undo changes logged.}
13
+ spec.license = 'MIT'
15
14
 
16
- s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
- s.require_paths = ["lib"]
15
+ spec.post_install_message = %q{Please run PgAuditLog::Function.install (in console/migration) to install the new versions of the database functions}
20
16
 
21
- s.add_dependency("rails", ">= 3.0.0")
22
- s.add_dependency("pg", ">= 0.9.0")
23
- s.add_development_dependency('rspec-rails', "= 2.7")
24
- s.add_development_dependency('with_model', '>= 0.1.3')
25
- s.add_development_dependency('autotest')
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'rails', '>= 3.2', '< 4.2'
23
+ spec.add_dependency 'pg', '>= 0.9.0'
24
+ spec.add_development_dependency 'rspec'
25
+ spec.add_development_dependency 'rspec-rails'
26
+ spec.add_development_dependency 'with_model', '>= 0.1.3'
26
27
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  describe "the PostgreSQL database" do
4
4
  after do
@@ -6,7 +6,6 @@ describe "the PostgreSQL database" do
6
6
  end
7
7
 
8
8
  it "has an audit log table" do
9
- ActiveRecord::Base.connection.table_exists?("audit_log").should be_true
9
+ ActiveRecord::Base.connection.table_exists?('audit_log').should be_true
10
10
  end
11
-
12
11
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  describe PgAuditLog::Function do
4
4
  describe ".installed?" do
@@ -7,6 +7,7 @@ describe PgAuditLog::Function do
7
7
  before do
8
8
  PgAuditLog::Function.uninstall
9
9
  end
10
+
10
11
  it { should be_false }
11
12
  end
12
13
 
@@ -14,6 +15,7 @@ describe PgAuditLog::Function do
14
15
  before do
15
16
  PgAuditLog::Function.install
16
17
  end
18
+
17
19
  it { should be_true }
18
20
  end
19
21
  end
@@ -24,9 +26,9 @@ describe PgAuditLog::Function do
24
26
 
25
27
  context "new style" do
26
28
  it "escapes the email" do
27
- subject.should_not match("SET")
29
+ subject.should_not match('SET')
28
30
 
29
- subject.should match("FUNCTION")
31
+ subject.should match('FUNCTION')
30
32
  subject.should match("'o''connell@fred.com'::varchar")
31
33
  end
32
34
  end
@@ -36,12 +38,14 @@ describe PgAuditLog::Function do
36
38
  Rails = double
37
39
  Rails.stub_chain(:configuration, :pg_audit_log_old_style_user_id).and_return(true)
38
40
  end
41
+
39
42
  after { Object.send(:remove_const, :Rails) }
43
+
40
44
  it "escapes the email" do
41
- subject.should match("SET")
45
+ subject.should match('SET')
42
46
  subject.should match("'o''connell@fred.com'")
43
47
 
44
- subject.should_not match("FUNCTION")
48
+ subject.should_not match('FUNCTION')
45
49
  subject.should_not match("'o''connell@fred.com'::varchar")
46
50
  end
47
51
  end
data/spec/model_spec.rb CHANGED
@@ -1,7 +1,6 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  describe PgAuditLog::Entry do
4
-
5
4
  subject { PgAuditLog::Entry.create! }
6
5
 
7
6
  describe ".delete" do
@@ -21,4 +20,4 @@ describe PgAuditLog::Entry do
21
20
  proc { subject.destroy }.should raise_error(PgAuditLog::Entry::CannotDeleteError)
22
21
  end
23
22
  end
24
- end
23
+ end
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  describe PgAuditLog do
4
4
  let(:connection) { ActiveRecord::Base.connection }
@@ -30,52 +30,51 @@ describe PgAuditLog do
30
30
  PgAuditLog::Entry.connection.execute("TRUNCATE #{PgAuditLog::Entry.quoted_table_name}")
31
31
  end
32
32
 
33
- let(:attributes) { { :str => "foo", :txt => "bar", :int => 5, :date => Date.today, :dt => Time.now.midnight } }
33
+ let(:attributes) { { :str => 'foo', :txt => 'bar', :int => 5, :date => Date.current, :dt => Time.current.midnight } }
34
34
 
35
35
  describe "on create" do
36
36
  context "the audit log record with a primary key" do
37
-
38
37
  before do
39
38
  AuditedModel.create!(attributes)
40
39
  end
41
40
 
42
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "str" }) }
41
+ subject { PgAuditLog::Entry.where(:field_name => 'str').last }
43
42
 
44
43
  it { should be }
45
44
  its(:occurred_at) { should be }
46
45
  its(:table_name) { should == AuditedModel.table_name }
47
- its(:field_name) { should == "str" }
46
+ its(:field_name) { should == 'str' }
48
47
  its(:primary_key) { should == AuditedModel.last.id.to_s }
49
- its(:operation) { should == "INSERT" }
48
+ its(:operation) { should == 'INSERT' }
50
49
 
51
50
  context "when a user is present" do
52
51
  before do
53
- Thread.current[:current_user] = stub("User", :id => 1, :unique_name => "my current user")
52
+ Thread.current[:current_user] = double('User', :id => 1, :unique_name => 'my current user')
54
53
  AuditedModel.create!
55
54
  end
56
55
 
57
56
  after { Thread.current[:current_user] = nil }
58
57
 
59
58
  its(:user_id) { should == 1 }
60
- its(:user_unique_name) { should == "my current user" }
59
+ its(:user_unique_name) { should == 'my current user' }
61
60
  end
62
61
 
63
62
  context "when no user is present" do
64
63
  its(:user_id) { should == -1 }
65
- its(:user_unique_name) { should == "UNKNOWN" }
64
+ its(:user_unique_name) { should == 'UNKNOWN' }
66
65
  end
67
66
 
68
67
  it "captures all new values for all fields" do
69
68
  attributes.each do |field_name, value|
69
+ entry = PgAuditLog::Entry.where(:field_name => field_name).last
70
70
  if field_name == :dt
71
- PgAuditLog::Entry.last(:conditions => { :field_name => field_name }).field_value_new.should == value.strftime("%Y-%m-%d %H:%M:%S")
71
+ entry.field_value_new.should == value.strftime("%Y-%m-%d %H:%M:%S")
72
72
  else
73
- PgAuditLog::Entry.last(:conditions => { :field_name => field_name }).field_value_new.should == value.to_s
73
+ entry.field_value_new.should == value.to_s
74
74
  end
75
- PgAuditLog::Entry.last(:conditions => { :field_name => field_name }).field_value_old.should be_nil
75
+ entry.field_value_old.should be_nil
76
76
  end
77
77
  end
78
-
79
78
  end
80
79
 
81
80
  context "the audit log record without a primary key" do
@@ -83,10 +82,10 @@ describe PgAuditLog do
83
82
  AuditedModelWithoutPrimaryKey.create!(attributes)
84
83
  end
85
84
 
86
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "str" }) }
85
+ subject { PgAuditLog::Entry.where(:field_name => 'str').last }
87
86
 
88
87
  it { should be }
89
- its(:field_name) { should == "str" }
88
+ its(:field_name) { should == 'str' }
90
89
  its(:primary_key) { should be_nil }
91
90
  end
92
91
  end
@@ -98,34 +97,34 @@ describe PgAuditLog do
98
97
  end
99
98
 
100
99
  context "when going from a value to a another value" do
101
- before { @model.update_attributes!(:str => "bar") }
102
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "str" }) }
100
+ before { @model.update_attributes!(:str => 'bar') }
101
+ subject { PgAuditLog::Entry.where(:field_name => 'str').last }
103
102
 
104
- its(:operation) { should == "UPDATE" }
105
- its(:field_value_new) { should == "bar" }
106
- its(:field_value_old) { should == "foo" }
103
+ its(:operation) { should == 'UPDATE' }
104
+ its(:field_value_new) { should == 'bar' }
105
+ its(:field_value_old) { should == 'foo' }
107
106
  end
108
107
 
109
108
  context "when going from nil to a value" do
110
109
  let(:attributes) { {:txt => nil} }
111
- before { @model.update_attributes!(:txt => "baz") }
112
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "txt" }) }
110
+ before { @model.update_attributes!(:txt => 'baz') }
111
+ subject { PgAuditLog::Entry.where(:field_name => 'txt').last }
113
112
 
114
- its(:field_value_new) { should == "baz" }
113
+ its(:field_value_new) { should == 'baz' }
115
114
  its(:field_value_old) { should be_nil }
116
115
  end
117
116
 
118
117
  context "when going from a value to nil" do
119
118
  before { @model.update_attributes!(:str => nil) }
120
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "str" }) }
119
+ subject { PgAuditLog::Entry.where(:field_name => 'str').last }
121
120
 
122
121
  its(:field_value_new) { should be_nil }
123
- its(:field_value_old) { should == "foo" }
122
+ its(:field_value_old) { should == 'foo' }
124
123
  end
125
124
 
126
125
  context "when the value does not change" do
127
- before { @model.update_attributes!(:str => "foo") }
128
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "str", :operation => "UPDATE" }) }
126
+ before { @model.update_attributes!(:str => 'foo') }
127
+ subject { PgAuditLog::Entry.where(:field_name => 'str', :operation => 'UPDATE').last }
129
128
 
130
129
  it { should_not be }
131
130
  end
@@ -133,18 +132,17 @@ describe PgAuditLog do
133
132
  context "when the value is nil and does not change" do
134
133
  let(:attributes) { {:txt => nil} }
135
134
  before { @model.update_attributes!(:txt => nil) }
136
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "txt", :operation => "UPDATE" }) }
135
+ subject { PgAuditLog::Entry.where(:field_name => 'txt', :operation => 'UPDATE').last }
137
136
 
138
137
  it { should_not be }
139
138
  end
140
139
 
141
140
  context "when the value is a boolean" do
142
-
143
141
  context "going from nil -> true" do
144
142
  before { @model.update_attributes!(:bool => true) }
145
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "bool", :operation => "UPDATE" }) }
143
+ subject { PgAuditLog::Entry.where(:field_name => 'bool', :operation => 'UPDATE').last }
146
144
 
147
- its(:field_value_new) { should == "true" }
145
+ its(:field_value_new) { should == 'true' }
148
146
  its(:field_value_old) { should be_nil }
149
147
  end
150
148
 
@@ -153,10 +151,10 @@ describe PgAuditLog do
153
151
  before do
154
152
  @model.update_attributes!(:bool => true)
155
153
  end
156
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "bool", :operation => "UPDATE" }) }
154
+ subject { PgAuditLog::Entry.where(:field_name => 'bool', :operation => 'UPDATE').last }
157
155
 
158
- its(:field_value_new) { should == "true" }
159
- its(:field_value_old) { should == "false" }
156
+ its(:field_value_new) { should == 'true' }
157
+ its(:field_value_old) { should == 'false' }
160
158
  end
161
159
 
162
160
  context "going from true -> false" do
@@ -165,48 +163,46 @@ describe PgAuditLog do
165
163
  before do
166
164
  @model.update_attributes!(:bool => false)
167
165
  end
168
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "bool", :operation => "UPDATE" }) }
166
+ subject { PgAuditLog::Entry.where(:field_name => 'bool', :operation => 'UPDATE').last }
169
167
 
170
- its(:field_value_new) { should == "false" }
171
- its(:field_value_old) { should == "true" }
168
+ its(:field_value_new) { should == 'false' }
169
+ its(:field_value_old) { should == 'true' }
172
170
  end
173
-
174
171
  end
175
172
  end
176
173
 
177
174
  context "the audit log record without a primary key" do
178
175
  before do
179
176
  AuditedModelWithoutPrimaryKey.create!(attributes)
180
- AuditedModelWithoutPrimaryKey.update_all(:str => "bar")
177
+ AuditedModelWithoutPrimaryKey.update_all(:str => 'bar')
181
178
  end
182
179
 
183
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "str" }) }
180
+ subject { PgAuditLog::Entry.where(:field_name => 'str').last }
184
181
 
185
182
  its(:primary_key) { should be_nil }
186
183
  end
187
-
188
184
  end
189
185
 
190
186
  describe "on delete" do
191
-
192
187
  context "the audit log record with a primary key" do
193
188
  before do
194
189
  model = AuditedModel.create!(attributes)
195
190
  model.delete
196
191
  end
197
192
 
198
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "str" }) }
193
+ subject { PgAuditLog::Entry.where(:field_name => 'str').last }
199
194
 
200
- its(:operation) { should == "DELETE" }
195
+ its(:operation) { should == 'DELETE' }
201
196
 
202
197
  it "captures all new values for all fields" do
203
198
  attributes.each do |field_name, value|
199
+ entry = PgAuditLog::Entry.where(:field_name => field_name).last
204
200
  if field_name == :dt
205
- PgAuditLog::Entry.last(:conditions => { :field_name => field_name }).field_value_old.should == value.strftime("%Y-%m-%d %H:%M:%S")
201
+ entry.field_value_old.should == value.strftime('%Y-%m-%d %H:%M:%S')
206
202
  else
207
- PgAuditLog::Entry.last(:conditions => { :field_name => field_name }).field_value_old.should == value.to_s
203
+ entry.field_value_old.should == value.to_s
208
204
  end
209
- PgAuditLog::Entry.last(:conditions => { :field_name => field_name }).field_value_new.should be_nil
205
+ entry.field_value_new.should be_nil
210
206
  end
211
207
  end
212
208
  end
@@ -217,7 +213,7 @@ describe PgAuditLog do
217
213
  AuditedModelWithoutPrimaryKey.delete_all
218
214
  end
219
215
 
220
- subject { PgAuditLog::Entry.last(:conditions => { :field_name => "str" }) }
216
+ subject { PgAuditLog::Entry.where(:field_name => 'str').last }
221
217
 
222
218
  its(:primary_key) { should be_nil }
223
219
  end
@@ -225,7 +221,7 @@ describe PgAuditLog do
225
221
 
226
222
  describe "performance" do
227
223
  xit "should perform well" do
228
- require "benchmark"
224
+ require 'benchmark'
229
225
  results = Benchmark.measure do
230
226
  1000.times do
231
227
  AuditedModel.create!(attributes)
@@ -238,29 +234,28 @@ describe PgAuditLog do
238
234
  end
239
235
 
240
236
  describe "during migrations" do
241
-
242
237
  before do
243
- connection.drop_table("test_table") rescue nil
244
- connection.drop_table("new_table") rescue nil
238
+ connection.drop_table('test_table') rescue nil
239
+ connection.drop_table('new_table') rescue nil
245
240
  end
246
241
 
247
242
  after do
248
- connection.drop_table("test_table") rescue nil
243
+ connection.drop_table('test_table') rescue nil
249
244
  end
250
245
 
251
246
  describe "when creating the table" do
252
247
  it "should automatically create the trigger" do
253
- PgAuditLog::Triggers.tables_with_triggers.should_not include("test_table")
254
- connection.create_table("test_table")
255
- PgAuditLog::Triggers.tables_with_triggers.should include("test_table")
248
+ PgAuditLog::Triggers.tables_with_triggers.should_not include('test_table')
249
+ connection.create_table('test_table')
250
+ PgAuditLog::Triggers.tables_with_triggers.should include('test_table')
256
251
  end
257
252
  end
258
253
 
259
254
  describe "when dropping the table" do
260
255
  it "should automatically drop the trigger" do
261
- connection.create_table("test_table")
262
- connection.drop_table("test_table")
263
- PgAuditLog::Triggers.tables_with_triggers.should_not include("test_table")
256
+ connection.create_table('test_table')
257
+ connection.drop_table('test_table')
258
+ PgAuditLog::Triggers.tables_with_triggers.should_not include('test_table')
264
259
  end
265
260
  end
266
261
 
@@ -274,11 +269,11 @@ describe PgAuditLog do
274
269
  end
275
270
 
276
271
  it "should automatically drop and create the trigger" do
277
- new_table_name = "new_table_#{Time.now.to_i}"
278
- connection.create_table("test_table")
279
- connection.rename_table("test_table", new_table_name)
272
+ new_table_name = "new_table_#{Time.current.to_i}"
273
+ connection.create_table('test_table')
274
+ connection.rename_table('test_table', new_table_name)
280
275
 
281
- trigger_names.should_not include("audit_test_table")
276
+ trigger_names.should_not include('audit_test_table')
282
277
  trigger_names.should include("audit_#{new_table_name}")
283
278
  PgAuditLog::Triggers.tables_with_triggers.should include(new_table_name)
284
279
 
@@ -290,16 +285,17 @@ describe PgAuditLog do
290
285
  describe "temporary tables" do
291
286
  context "when creating them" do
292
287
  it "should be ignored" do
293
- connection.create_table("some_temp_table", :temporary => true)
294
- PgAuditLog::Triggers.tables_with_triggers.should_not include("some_temp_table")
295
- connection.drop_table("some_temp_table")
288
+ connection.create_table('some_temp_table', :temporary => true)
289
+ PgAuditLog::Triggers.tables_with_triggers.should_not include('some_temp_table')
290
+ connection.drop_table('some_temp_table')
296
291
  end
297
292
  end
293
+
298
294
  context "when dropping them" do
299
295
  it "should be ignored" do
300
- connection.create_table("some_temp_table", :temporary => true)
301
- connection.drop_table("some_temp_table")
302
- PgAuditLog::Triggers.tables_with_triggers.should_not include("some_temp_table")
296
+ connection.create_table('some_temp_table', :temporary => true)
297
+ connection.drop_table('some_temp_table')
298
+ PgAuditLog::Triggers.tables_with_triggers.should_not include('some_temp_table')
303
299
  end
304
300
  end
305
301
  end
@@ -311,9 +307,9 @@ describe PgAuditLog do
311
307
 
312
308
  context "when creating a table" do
313
309
  it "should install the function then enable the trigger on the table" do
314
- connection.create_table("some_more_new_table")
315
- PgAuditLog::Triggers.tables_with_triggers.should include("some_more_new_table")
316
- connection.drop_table("some_more_new_table")
310
+ connection.create_table('some_more_new_table')
311
+ PgAuditLog::Triggers.tables_with_triggers.should include('some_more_new_table')
312
+ connection.drop_table('some_more_new_table')
317
313
  end
318
314
  end
319
315
  end
@@ -326,9 +322,9 @@ describe PgAuditLog do
326
322
  context "when creating a table" do
327
323
  it "should install the entry table then enable the trigger on the table" do
328
324
  PgAuditLog::Entry.installed?.should be_false
329
- connection.create_table("another_table")
325
+ connection.create_table('another_table')
330
326
  PgAuditLog::Entry.installed?.should be_true
331
- connection.drop_table("another_table")
327
+ connection.drop_table('another_table')
332
328
  end
333
329
  end
334
330
  end
@@ -336,12 +332,11 @@ describe PgAuditLog do
336
332
  describe "ignored tables" do
337
333
  context "when creating one of those tables" do
338
334
  it "should not automatically create a trigger for it" do
339
- PgAuditLog::IGNORED_TABLES << "ignored_table"
340
- connection.create_table("ignored_table")
341
- PgAuditLog::Triggers.tables_with_triggers.should_not include("ignored_table")
342
- connection.drop_table("ignored_table")
335
+ PgAuditLog::IGNORED_TABLES << 'ignored_table'
336
+ connection.create_table('ignored_table')
337
+ PgAuditLog::Triggers.tables_with_triggers.should_not include('ignored_table')
338
+ connection.drop_table('ignored_table')
343
339
  end
344
340
  end
345
341
  end
346
-
347
342
  end
data/spec/spec_helper.rb CHANGED
@@ -1,23 +1,29 @@
1
- require "bundler/setup"
2
- require "pg_audit_log"
3
- require "with_model"
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ require 'pg_audit_log'
5
+ require 'with_model'
4
6
 
5
7
  connection = nil
6
8
  begin
7
- ActiveRecord::Base.establish_connection(:adapter => 'postgresql',
8
- :database => 'pg_audit_log_test',
9
- :min_messages => 'warning')
9
+ ActiveRecord::Base.establish_connection({
10
+ :adapter => 'postgresql',
11
+ :database => 'pg_audit_log_test',
12
+ :min_messages => 'warning',
13
+ })
10
14
  connection = ActiveRecord::Base.connection
11
- connection.execute("SELECT 1")
15
+ connection.execute('SELECT 1')
12
16
  rescue PGError => e
13
- puts "-" * 80
14
- puts "Unable to connect to database. Please run:"
17
+ puts '-' * 80
18
+ puts 'Unable to connect to database. Please run:'
15
19
  puts
16
- puts " createdb pg_audit_log_test"
17
- puts "-" * 80
20
+ puts ' createdb pg_audit_log_test'
21
+ puts '-' * 80
18
22
  raise e
19
23
  end
20
24
 
25
+ ActiveRecord::Base.default_timezone = :local
26
+
21
27
  RSpec.configure do |config|
22
28
  config.mock_with :rspec
23
29
  config.extend WithModel
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  describe PgAuditLog::Triggers do
4
4
  before :each do
@@ -155,7 +155,5 @@ describe PgAuditLog::Triggers do
155
155
  end
156
156
  end
157
157
  end
158
-
159
158
  end
160
159
  end
161
-
metadata CHANGED
@@ -1,88 +1,108 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pg_audit_log
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.6
5
- prerelease:
4
+ version: 0.6.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Case Commons, LLC
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-09-27 00:00:00.000000000 Z
11
+ date: 2014-05-16 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rails
16
- requirement: &70199944309260 !ruby/object:Gem::Requirement
17
- none: false
15
+ requirement: !ruby/object:Gem::Requirement
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
- version: 3.0.0
19
+ version: '3.2'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '4.2'
22
23
  type: :runtime
23
24
  prerelease: false
24
- version_requirements: *70199944309260
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3.2'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '4.2'
25
33
  - !ruby/object:Gem::Dependency
26
34
  name: pg
27
- requirement: &70199944308760 !ruby/object:Gem::Requirement
28
- none: false
35
+ requirement: !ruby/object:Gem::Requirement
29
36
  requirements:
30
- - - ! '>='
37
+ - - ">="
31
38
  - !ruby/object:Gem::Version
32
39
  version: 0.9.0
33
40
  type: :runtime
34
41
  prerelease: false
35
- version_requirements: *70199944308760
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.9.0
36
47
  - !ruby/object:Gem::Dependency
37
- name: rspec-rails
38
- requirement: &70199944308300 !ruby/object:Gem::Requirement
39
- none: false
48
+ name: rspec
49
+ requirement: !ruby/object:Gem::Requirement
40
50
  requirements:
41
- - - =
51
+ - - ">="
42
52
  - !ruby/object:Gem::Version
43
- version: '2.7'
53
+ version: '0'
44
54
  type: :development
45
55
  prerelease: false
46
- version_requirements: *70199944308300
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
47
61
  - !ruby/object:Gem::Dependency
48
- name: with_model
49
- requirement: &70199944307840 !ruby/object:Gem::Requirement
50
- none: false
62
+ name: rspec-rails
63
+ requirement: !ruby/object:Gem::Requirement
51
64
  requirements:
52
- - - ! '>='
65
+ - - ">="
53
66
  - !ruby/object:Gem::Version
54
- version: 0.1.3
67
+ version: '0'
55
68
  type: :development
56
69
  prerelease: false
57
- version_requirements: *70199944307840
58
- - !ruby/object:Gem::Dependency
59
- name: autotest
60
- requirement: &70199944307460 !ruby/object:Gem::Requirement
61
- none: false
70
+ version_requirements: !ruby/object:Gem::Requirement
62
71
  requirements:
63
- - - ! '>='
72
+ - - ">="
64
73
  - !ruby/object:Gem::Version
65
74
  version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: with_model
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 0.1.3
66
82
  type: :development
67
83
  prerelease: false
68
- version_requirements: *70199944307460
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 0.1.3
69
89
  description: A completely transparent audit logging component for your application
70
90
  using a stored procedure and triggers. Comes with specs for your project and a rake
71
- task to generate the reverse SQL to undo changes logged
91
+ task to generate the reverse SQL to undo changes logged.
72
92
  email:
73
93
  - casecommons-dev@googlegroups.com
74
94
  executables: []
75
95
  extensions: []
76
96
  extra_rdoc_files: []
77
97
  files:
78
- - .gitignore
79
- - .rspec
80
- - .rvmrc
98
+ - ".gitignore"
99
+ - ".rspec"
100
+ - ".rvmrc"
101
+ - ".travis.yml"
81
102
  - Gemfile
82
103
  - LICENSE
83
- - README.rdoc
104
+ - README.md
84
105
  - Rakefile
85
- - init.rb
86
106
  - lib/generators/pg_audit_log/install_generator.rb
87
107
  - lib/generators/pg_audit_log/rspec_generator.rb
88
108
  - lib/generators/pg_audit_log/templates/lib/tasks/pg_audit_log.rake
@@ -104,36 +124,30 @@ files:
104
124
  - spec/spec_helper.rb
105
125
  - spec/triggers_spec.rb
106
126
  homepage: https://github.com/Casecommons/pg_audit_log
107
- licenses: []
127
+ licenses:
128
+ - MIT
129
+ metadata: {}
108
130
  post_install_message: Please run PgAuditLog::Function.install (in console/migration)
109
131
  to install the new versions of the database functions
110
132
  rdoc_options: []
111
133
  require_paths:
112
134
  - lib
113
135
  required_ruby_version: !ruby/object:Gem::Requirement
114
- none: false
115
136
  requirements:
116
- - - ! '>='
137
+ - - ">="
117
138
  - !ruby/object:Gem::Version
118
139
  version: '0'
119
- segments:
120
- - 0
121
- hash: 1103642768265560851
122
140
  required_rubygems_version: !ruby/object:Gem::Requirement
123
- none: false
124
141
  requirements:
125
- - - ! '>='
142
+ - - ">="
126
143
  - !ruby/object:Gem::Version
127
144
  version: '0'
128
- segments:
129
- - 0
130
- hash: 1103642768265560851
131
145
  requirements: []
132
146
  rubyforge_project:
133
- rubygems_version: 1.8.17
147
+ rubygems_version: 2.2.2
134
148
  signing_key:
135
- specification_version: 3
136
- summary: postgresql only database-level audit logging of all databases changes
149
+ specification_version: 4
150
+ summary: PostgreSQL-only database-level audit logging of all databases changes.
137
151
  test_files:
138
152
  - spec/configuration_spec.rb
139
153
  - spec/function_spec.rb
@@ -141,3 +155,4 @@ test_files:
141
155
  - spec/pg_audit_log_spec.rb
142
156
  - spec/spec_helper.rb
143
157
  - spec/triggers_spec.rb
158
+ has_rdoc:
data/README.rdoc DELETED
@@ -1,62 +0,0 @@
1
- = pg_audit_log
2
-
3
- * http://github.com/casecommons/pg_audit_log/
4
-
5
- == DESCRIPTION
6
-
7
- PostgreSQL only database-level audit logging of all databases changes using a completely transparent stored procedure and triggers.
8
- Comes with specs for your project and a rake task to generate the reverse SQL to undo changes logged}
9
-
10
- All SQL INSERTs, UPDATEs, and DELETEs will be captured. Record columns that do not change do not generate an audit log entry.
11
-
12
- Compatible with Rails 3.0.x, 3.1.x and 3.2.x
13
-
14
- On a 2.93GHz i7 with postgresql 9.1 the audit log has an overhead of about 0.0035 seconds to each INSERT, UPDATE or DELETE
15
-
16
- == INSTALL
17
-
18
- === Enable plpgsql langauges in your postgresql instance
19
-
20
- As a superuser in postgres make sure your database has plpgsql enabled:
21
-
22
- CREATE OR REPLACE PROCEDURAL LANGUAGE plpgsql;
23
-
24
- === Rails 3
25
-
26
- $ rails generate pg_audit_log:install
27
-
28
- === Installing the PostgreSQL function and triggers for your project
29
-
30
- $ rake pg_audit_log:install
31
-
32
- == Using on your project
33
-
34
- The PgAuditLog::Entry ActiveRecord model represents a single entry in the audit log table. Each entry represents a single change to a single field of a record in a table. So if you change 3 columns of a record, that will generate 3 corresponding PgAuditLog::Entry records.
35
-
36
- You can see the SQL it injects on every query by running with LOG_AUDIT_SQL
37
-
38
- === Migrations
39
-
40
- TODO
41
-
42
- === schema.rb and development_structure.sql
43
-
44
- Since schema.rb cannot represent TRIGGERs or FUNCTIONs you will need to set your environment to generate SQL instead of ruby for your database schema and structure. In your application environment put the following:
45
-
46
- config.active_record.schema_format = :sql
47
-
48
- And you can generate this sql using:
49
-
50
- $ rake db:structure:dump
51
-
52
- === Uninstalling
53
-
54
- $ rake pg_audit_log:uninstall
55
-
56
- == REQUIREMENTS
57
-
58
- * ActiveRecord
59
-
60
- == LICENSE
61
-
62
- MIT
data/init.rb DELETED
@@ -1 +0,0 @@
1
- require "pg_audit_log"