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 'active_model_serializers'
gem 'paper_trail'
# AUTHORIZATION
gem 'pundit'

View file

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

View file

@ -24,7 +24,8 @@ class Admin::CardsController < Admin::BaseController
authorize @card
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
render :new
end
@ -32,13 +33,16 @@ class Admin::CardsController < Admin::BaseController
def edit
authorize @card
@versions = @card.versions
end
def update
authorize @card
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
render :edit
end
@ -49,7 +53,8 @@ class Admin::CardsController < Admin::BaseController
@card.destroy
redirect_to admin_cards_path, notice: 'Card was deleted'
redirect_to admin_cards_path,
notice: "Card was deleted. #{undo_link(@card)}"
end
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
has_paper_trail
validates :name, presence: true
end

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1 +1,3 @@
== 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'
span aria-hidden='true' &times;
span.sr-only Close
= message
= raw(message)

View file

@ -12,6 +12,8 @@ Rails.application.routes.draw do
get '/dashboard', to: 'dashboard#index'
post '/versions/revert', to: 'versions#revert', as: 'revert_version'
resources :awaken_types
resources :cards
resources :characters
@ -22,6 +24,7 @@ Rails.application.routes.draw do
resources :super_attacks
resources :types
resources :users, except: [:new, :create]
resources :versions, only: [:show]
end
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.
ActiveRecord::Schema.define(version: 20151008192100) do
ActiveRecord::Schema.define(version: 20151014121824) do
create_table "awaken_types", force: :cascade do |t|
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"
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