1
0
Fork 0

Merge branch 'atomaka/feature/paper_trail' into 'master'

Implement version tracking and undoing

Add version tracking using the paper_trail gem.  All models are currently being tracked. However, UI has only been implemented for the Cards model.  Cards will show a list of all previous versions when editing them.  Undoing was also implemented for cards.  Whenever any create, edit, or delete is performed, the flash notice will include an undo link that can be used to revert the change.

paper_trail does not track `has_and_belongs_to_many` so `link` changes will not be tracked.

See merge request !2
This commit is contained in:
Andrew Tomaka 2015-10-14 10:03:00 -04:00
commit d319211044
28 changed files with 212 additions and 5 deletions

View file

@ -16,6 +16,7 @@ gem 'simple_form'
gem 'omniauth-reddit', :git => 'git://github.com/jackdempsey/omniauth-reddit.git' gem 'omniauth-reddit', :git => 'git://github.com/jackdempsey/omniauth-reddit.git'
gem 'active_model_serializers' gem 'active_model_serializers'
gem 'paper_trail'
# AUTHORIZATION # AUTHORIZATION
gem 'pundit' gem 'pundit'

View file

@ -118,6 +118,10 @@ GEM
omniauth-oauth2 (1.3.1) omniauth-oauth2 (1.3.1)
oauth2 (~> 1.0) oauth2 (~> 1.0)
omniauth (~> 1.2) omniauth (~> 1.2)
paper_trail (4.0.0)
activerecord (>= 3.0, < 6.0)
activesupport (>= 3.0, < 6.0)
request_store (~> 1.1)
pg (0.18.3) pg (0.18.3)
puma (2.14.0) puma (2.14.0)
pundit (1.0.1) pundit (1.0.1)
@ -163,6 +167,7 @@ GEM
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rake (10.4.2) rake (10.4.2)
rdoc (4.2.0) rdoc (4.2.0)
request_store (1.2.0)
rolify (4.1.1) rolify (4.1.1)
ruby-graphviz (1.2.2) ruby-graphviz (1.2.2)
sass (3.4.18) sass (3.4.18)
@ -225,6 +230,7 @@ DEPENDENCIES
jbuilder (~> 2.0) jbuilder (~> 2.0)
jquery-rails jquery-rails
omniauth-reddit! omniauth-reddit!
paper_trail
pg pg
puma puma
pundit pundit

View file

@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

View file

@ -0,0 +1,3 @@
// Place all the styles related to the Admin::Versions controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/

View file

@ -1,3 +1,11 @@
class Admin::BaseController < ApplicationController class Admin::BaseController < ApplicationController
layout 'admin' layout 'admin'
private
def undo_link(item)
view_context.link_to('Undo this change',
admin_revert_version_path(id: item.version.last),
method: :post)
end
end end

View file

@ -24,7 +24,8 @@ class Admin::CardsController < Admin::BaseController
authorize @card authorize @card
if @card.save if @card.save
redirect_to admin_cards_path, notice: 'Card was created' redirect_to admin_cards_path,
notice: "Card was created. #{undo_link(@card)}"
else else
render :new render :new
end end
@ -32,13 +33,16 @@ class Admin::CardsController < Admin::BaseController
def edit def edit
authorize @card authorize @card
@versions = @card.versions
end end
def update def update
authorize @card authorize @card
if @card.update(card_params) if @card.update(card_params)
redirect_to admin_cards_path, notice: 'Card was updated' redirect_to admin_cards_path,
notice: "Card was updated. #{undo_link(@card)}"
else else
render :edit render :edit
end end
@ -49,7 +53,8 @@ class Admin::CardsController < Admin::BaseController
@card.destroy @card.destroy
redirect_to admin_cards_path, notice: 'Card was deleted' redirect_to admin_cards_path,
notice: "Card was deleted. #{undo_link(@card)}"
end end
private private

View file

@ -0,0 +1,27 @@
class Admin::VersionsController < Admin::BaseController
def show
@version = PaperTrail::Version.find(params[:id]).reify(has_one: true)
type = @version.class.to_s.underscore
instance_variable_set('@' + type, @version)
render "admin/#{type.pluralize}/show"
end
def revert
@version = PaperTrail::Version.find(params[:id])
if @version.reify(has_one: true)
@version.reify(has_one: true).save!
else
@version.item.destroy
end
redirect_to :back, notice: "Undid #{@version.event}!"
end
private
def set_version
end
end

View file

@ -0,0 +1,2 @@
module Admin::VersionsHelper
end

View file

@ -1,3 +1,5 @@
class AwakenType < ActiveRecord::Base class AwakenType < ActiveRecord::Base
has_paper_trail
validates :name, presence: true validates :name, presence: true
end end

View file

@ -1,4 +1,6 @@
class Card < ActiveRecord::Base class Card < ActiveRecord::Base
has_paper_trail
belongs_to :character belongs_to :character
belongs_to :rarity belongs_to :rarity
belongs_to :type belongs_to :type

View file

@ -1,4 +1,6 @@
class Character < ActiveRecord::Base class Character < ActiveRecord::Base
has_paper_trail
validates :name, presence: true, validates :name, presence: true,
uniqueness: { case_sensitive: false } uniqueness: { case_sensitive: false }

View file

@ -1,3 +1,5 @@
class LeaderSkill < ActiveRecord::Base class LeaderSkill < ActiveRecord::Base
has_paper_trail
validates :description, presence: true validates :description, presence: true
end end

View file

@ -1,4 +1,6 @@
class Link < ActiveRecord::Base class Link < ActiveRecord::Base
has_paper_trail
has_and_belongs_to_many :cards has_and_belongs_to_many :cards
validates :name, presence: true, validates :name, presence: true,

View file

@ -1,4 +1,6 @@
class PassiveSkill < ActiveRecord::Base class PassiveSkill < ActiveRecord::Base
has_paper_trail
validates :name, presence: true validates :name, presence: true
validates :description, presence: true validates :description, presence: true

View file

@ -1,4 +1,6 @@
class Rarity < ActiveRecord::Base class Rarity < ActiveRecord::Base
has_paper_trail
validates :name, presence: true, validates :name, presence: true,
uniqueness: { case_sensitive: false } uniqueness: { case_sensitive: false }
validates :description, presence: true validates :description, presence: true

View file

@ -1,4 +1,6 @@
class SuperAttack < ActiveRecord::Base class SuperAttack < ActiveRecord::Base
has_paper_trail
validates :name, presence: true validates :name, presence: true
validates :description, presence: true validates :description, presence: true

View file

@ -1,4 +1,6 @@
class Type < ActiveRecord::Base class Type < ActiveRecord::Base
has_paper_trail
validates :name, presence: true, validates :name, presence: true,
uniqueness: { case_sensitive: false } uniqueness: { case_sensitive: false }
validates :description, presence: true validates :description, presence: true

View file

@ -1,4 +1,5 @@
class User < ActiveRecord::Base class User < ActiveRecord::Base
has_paper_trail
rolify rolify
after_create :set_admin, if: :first_user? after_create :set_admin, if: :first_user?

View file

@ -1 +1,3 @@
== render 'form' == render 'form'
== render 'admin/versions/list', versions: @versions

View file

@ -0,0 +1,42 @@
.row
.col-md-4
strong Game ID Number:
= @card.gameid
.col-md-4
strong Title:
= @card.title
.col-md-4
strong Character:
= @card.character.name
.row
.col-md-4
strong Rarity:
= @card.rarity.name
.col-md-4
strong Type:
= @card.type.name
.col-md-4
strong Awaken Type:
= @card.awaken_type.name
.row
.col-md-6
strong Leader Skill:
= @card.leader_skill.description
.col-md-6
strong Passive Skill:
= @card.passive_skill.name
.row
.col-md-12
strong Super Attack:
= "#{@card.super_attack.name} - #{@card.super_attack.description}"
.row
.col-md-6
strong Dokkan Card:
- if @card.dokkan_card
= @card.dokkan_card.full_name
.row
.col-md-12
strong Links:
ul
- @card.links.each do |link|
li= link.name

View file

@ -0,0 +1,16 @@
.row
.col-md-12
table.table.table-striped.table-hover
thead
tr
th ID
th Event
th Date
th Modified By
tbody
- versions.each do |version|
tr
td= link_to version.id, admin_version_path(version)
td= version.event
td= version.created_at
td= User.find(version.version_author).nickname

View file

View file

@ -2,4 +2,4 @@
button.close type='button' data-dismiss='alert' button.close type='button' data-dismiss='alert'
span aria-hidden='true' &times; span aria-hidden='true' &times;
span.sr-only Close span.sr-only Close
= message = raw(message)

View file

@ -12,6 +12,8 @@ Rails.application.routes.draw do
get '/dashboard', to: 'dashboard#index' get '/dashboard', to: 'dashboard#index'
post '/versions/revert', to: 'versions#revert', as: 'revert_version'
resources :awaken_types resources :awaken_types
resources :cards resources :cards
resources :characters resources :characters
@ -22,6 +24,7 @@ Rails.application.routes.draw do
resources :super_attacks resources :super_attacks
resources :types resources :types
resources :users, except: [:new, :create] resources :users, except: [:new, :create]
resources :versions, only: [:show]
end end
namespace :api do namespace :api do

View file

@ -0,0 +1,20 @@
class CreateVersions < ActiveRecord::Migration
# The largest text column available in all supported RDBMS is
# 1024^3 - 1 bytes, roughly one gibibyte. We specify a size
# so that MySQL will use `longtext` instead of `text`. Otherwise,
# when serializing very large objects, `text` might not be big enough.
TEXT_BYTES = 1_073_741_823
def change
create_table :versions do |t|
t.string :item_type, :null => false
t.integer :item_id, :null => false
t.string :event, :null => false
t.string :whodunnit
t.text :object, :limit => TEXT_BYTES
t.datetime :created_at
end
add_index :versions, [:item_type, :item_id]
end
end

View file

@ -0,0 +1,17 @@
class CreateVersionAssociations < ActiveRecord::Migration
def self.up
create_table :version_associations do |t|
t.integer :version_id
t.string :foreign_key_name, :null => false
t.integer :foreign_key_id
end
add_index :version_associations, [:version_id]
add_index :version_associations, [:foreign_key_name, :foreign_key_id], :name => 'index_version_associations_on_foreign_key'
end
def self.down
remove_index :version_associations, [:version_id]
remove_index :version_associations, :name => 'index_version_associations_on_foreign_key'
drop_table :version_associations
end
end

View file

@ -0,0 +1,11 @@
class AddTransactionIdColumnToVersions < ActiveRecord::Migration
def self.up
add_column :versions, :transaction_id, :integer
add_index :versions, [:transaction_id]
end
def self.down
remove_index :versions, [:transaction_id]
remove_column :versions, :transaction_id
end
end

View file

@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20151008192100) do ActiveRecord::Schema.define(version: 20151014121824) do
create_table "awaken_types", force: :cascade do |t| create_table "awaken_types", force: :cascade do |t|
t.string "name" t.string "name"
@ -134,4 +134,26 @@ ActiveRecord::Schema.define(version: 20151008192100) do
add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id" add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id"
create_table "version_associations", force: :cascade do |t|
t.integer "version_id"
t.string "foreign_key_name", null: false
t.integer "foreign_key_id"
end
add_index "version_associations", ["foreign_key_name", "foreign_key_id"], name: "index_version_associations_on_foreign_key"
add_index "version_associations", ["version_id"], name: "index_version_associations_on_version_id"
create_table "versions", force: :cascade do |t|
t.string "item_type", null: false
t.integer "item_id", null: false
t.string "event", null: false
t.string "whodunnit"
t.text "object", limit: 1073741823
t.datetime "created_at"
t.integer "transaction_id"
end
add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id"
add_index "versions", ["transaction_id"], name: "index_versions_on_transaction_id"
end end