Skip to content

Commit

Permalink
Implement same functionality using temporary functions in the pg_temp…
Browse files Browse the repository at this point in the history
… namespace and do away with needing a custom variable. Fixes #1
  • Loading branch information
schubert committed Oct 3, 2011
1 parent a7d5fa7 commit eb3d508
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 35 deletions.
14 changes: 3 additions & 11 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,11 @@ Compatible with Rails 3.0.x and 3.1.x

== INSTALL

=== Enable custom variables in your postgresql instance
=== Enable plpgsql langauges in your postgresql instance

To enable auditing you need to set a variable in your postgresql.conf file:
As a superuser in postgres make sure your database has plpgsql enabled:

For macports: /opt/local/var/db/postgresql84/defaultdb/postgresql.conf
For homebrew: /usr/local/var/postgres/postgresql.conf
For linux: it varies from distro to distro.

At the bottom of the file add the following:

custom_variable_classes = 'audit'

Then restart your PostgreSQL server
CREATE OR REPLACE PROCEDURAL LANGUAGE plpgsql;

=== Rails 3

Expand Down
8 changes: 3 additions & 5 deletions lib/pg_audit_log/extensions/3.0/postgresql_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
# Did not want to reopen the class but sending an include seemingly is not working.
class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
def execute_with_auditing(sql, name = nil)
current_user = Thread.current[:current_user]
user_unique_name = current_user.try(:unique_name) || "UNKNOWN"

log_user_id = %[SET audit.user_id = #{current_user.try(:id) || "-1"}]
log_user_unique_name = %[SET audit.user_unique_name = "#{user_unique_name}"]
user_id, unique_name = user_id_and_name
log_user_id = PgAuditLog::Function.user_identifier_temporary_function(user_id)
log_user_unique_name = PgAuditLog::Function.user_unique_name_temporary_function(unique_name)

log([log_user_id, log_user_unique_name, sql].join("; "), name) do
if @async
Expand Down
8 changes: 3 additions & 5 deletions lib/pg_audit_log/extensions/3.1/postgresql_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
# Did not want to reopen the class but sending an include seemingly is not working.
class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
def generate_auditing_sql(sql)
current_user = Thread.current[:current_user]
user_unique_name = current_user.try(:unique_name) || "UNKNOWN"

log_user_id = %[SET audit.user_id = #{current_user.try(:id) || "-1"}]
log_user_unique_name = %[SET audit.user_unique_name = "#{user_unique_name}"]
user_id, unique_name = user_id_and_name
log_user_id = PgAuditLog::Function.user_identifier_temporary_function(user_id)
log_user_unique_name = PgAuditLog::Function.user_unique_name_temporary_function(unique_name)
{ :user_id => log_user_id, :unique_name => log_user_unique_name, :sql => sql }
end

Expand Down
9 changes: 9 additions & 0 deletions lib/pg_audit_log/extensions/shared/postgresql_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,13 @@ def rename_table_with_auditing(table_name, new_name)
end
alias_method_chain :rename_table, :auditing

private

def user_id_and_name
current_user = Thread.current[:current_user]
user_id = current_user.try(:id) || "-1"
user_unique_name = current_user.try(:unique_name) || "UNKNOWN"
return [user_id, user_unique_name]
end

end
32 changes: 26 additions & 6 deletions lib/pg_audit_log/function.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ def name
"audit_changes"
end

def custom_variable
"audit"
end

def users_table_name
"users"
end
Expand All @@ -25,6 +21,30 @@ def users_access_column
"last_accessed_at"
end

def user_identifier_temporary_function(user_id)
sql = <<-SQL
CREATE OR REPLACE FUNCTION pg_temp.pg_audit_log_user_identifier() RETURNS integer
LANGUAGE plpgsql
AS $_$
BEGIN
RETURN #{user_id};
END
$_$;
SQL
end

def user_unique_name_temporary_function(username)
sql = <<-SQL
CREATE OR REPLACE FUNCTION pg_temp.pg_audit_log_user_unique_name() RETURNS varchar
LANGUAGE plpgsql
AS $_$
BEGIN
RETURN '#{username}';
END
$_$;
SQL
end

def install
execute <<-SQL
CREATE OR REPLACE PROCEDURAL LANGUAGE plpgsql;
Expand All @@ -46,8 +66,8 @@ def install
old_value := NULL;
primary_key_column := NULL;
primary_key_value := NULL;
user_identifier := current_setting('#{custom_variable}.#{user_id_field}');
unique_name := current_setting('#{custom_variable}.#{user_name_field}');
user_identifier := pg_temp.pg_audit_log_user_identifier();
unique_name := pg_temp.pg_audit_log_user_unique_name();
column_name := col.column_name;
EXECUTE 'SELECT pg_attribute.attname
Expand Down
2 changes: 1 addition & 1 deletion lib/pg_audit_log/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module PgAuditLog
VERSION = "0.3.6"
VERSION = "0.4.0"
end
8 changes: 1 addition & 7 deletions spec/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,8 @@
ActiveRecord::Base.connection.reconnect!
end

it "allows custom class variables for audit" do
lambda {
ActiveRecord::Base.connection.execute('SET audit.test = 1')
}.should_not raise_error(ActiveRecord::StatementInvalid), "Your postgres is not configured for auditing. See README.rdoc"
end

it "has an audit log table" do
ActiveRecord::Base.connection.table_exists?("audit_log").should be_true
end

end
end

0 comments on commit eb3d508

Please sign in to comment.