Skip to content

Auditing via paper_trail (change history)

Daxter edited this page May 23, 2012 · 14 revisions

paper_trail is a gem used for auditing and versioning of your models. We can easily use it with active_admin to show a list of recently modified items in the admin screen.

Example:

Integration instructions

  1. Install PaperTrail as a gem via your Gemfile:

    gem 'paper_trail'

  2. Generate a migration which will add a versions table to your database:

    rails generate paper_trail:install

  3. Run the migration:

    rake db:migrate

  4. Add user_for_paper_trail to controller so paper_trail knows which user updated the item. (optional)

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  # ...
  protected

  def user_for_paper_trail
    admin_user_signed_in? ? current_admin_user : 'Unknown user'
  end
  # ...
end
  1. Add has_paper_trail to the models you want to track:
# app/models/post.rb
class Post < ActiveRecord::Base
  has_paper_trail
  # ...
end
  1. Display the versions table on the dashboard
# app/admin/dashboard.rb
section "Recently updated content" do
  table_for Version.order('id desc').limit(20) do
    column "Item" do |v| v.item end
    column "Type" do |v| v.item_type.underscore.humanize end
    column "Modified at" do |v| v.created_at.to_s :long end
    column "Admin" do |v| link_to AdminUser.find(v.whodunnit).email, admin_admin_user_path(AdminUser.find(v.whodunnit)) end
  end
end

Linking to model

To link the item column to your model in active_admin, I added the following method to my model:

# app/models/post.rb
class Post < ActiveRecord::Base
  include Rails.application.routes.url_helpers # neeeded for _path helpers to work in models
      
  has_paper_trail
  # ...
  def admin_permalink
    admin_post_path(self)
  end
  # ...
end

Then in app/admin/dashboard.rb:

column "Item" do |v| link_to v.item, v.item.admin_permalink end

Versioning models

in app/admin/posts.rb:

controller do
  def show
      @post = Post.find(params[:id])
      @versions = @post.versions 
      @post = @post.versions[params[:version].to_i].reify if params[:version]
      show! #it seems to need this
  end
end
  sidebar :versionate, :partial => "layouts/version", :only => :show

then create the partial in app/views/layouts/_version.html.erb with this:

<h3>Current Version: <%= @versions.length %></h3>

<b>Created At:</b>
<%= @versions.last.created_at%>
<br>
<b>Admin</b>: <%= @versions.last.whodunnit %>
<br>
<% if @versions.length.to_i > 1 %>
  <% if params[:version].to_i > 1 || !params[:version] %>
    <%= link_to "Previous version", {:version => (params[:version] || @versions.length).to_i - 1}%>
    <br>
  <% end %>
  <% if params[:version] %>
    <h3>This is <%= "#{params[:version]}"%> version</h3>

    <b>Modify at:</b>
    <%= @versions[(params[:version].to_i - 1)].created_at %>
    <br>
    <b>Admin</b>:
    <%= @versions[(params[:version].to_i - 1)].whodunnit %>
    <br>

    <%= link_to "Go to current version"%>
  <% end %>
<% end %>

###Adding a history page. you can add it including a member action. like this in admin/posts.rb add

...
  member_action :history do
    @post = Post.find(params[:id])
    @versions = @post.versions
    render "layouts/history"
  end
...

Then create the file app/views/layouts/history.html.arb with

panel "Historia" do
  table_for assigns[:versions]
end

Visit /admin/post/:id/history to see history for a particular post.

Clone this wiki locally