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:
commit
d319211044
28 changed files with 212 additions and 5 deletions
1
Gemfile
1
Gemfile
|
@ -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'
|
||||||
|
|
|
@ -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
|
||||||
|
|
3
app/assets/javascripts/admin/versions.coffee
Normal file
3
app/assets/javascripts/admin/versions.coffee
Normal 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/
|
3
app/assets/stylesheets/admin/versions.scss
Normal file
3
app/assets/stylesheets/admin/versions.scss
Normal 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/
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
27
app/controllers/admin/versions_controller.rb
Normal file
27
app/controllers/admin/versions_controller.rb
Normal 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
|
2
app/helpers/admin/versions_helper.rb
Normal file
2
app/helpers/admin/versions_helper.rb
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
module Admin::VersionsHelper
|
||||||
|
end
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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?
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
== render 'form'
|
== render 'form'
|
||||||
|
|
||||||
|
== render 'admin/versions/list', versions: @versions
|
||||||
|
|
42
app/views/admin/cards/show.html.slim
Normal file
42
app/views/admin/cards/show.html.slim
Normal 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
|
16
app/views/admin/versions/_list.html.slim
Normal file
16
app/views/admin/versions/_list.html.slim
Normal 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
|
0
app/views/admin/versions/show.html.slim
Normal file
0
app/views/admin/versions/show.html.slim
Normal file
|
@ -2,4 +2,4 @@
|
||||||
button.close type='button' data-dismiss='alert'
|
button.close type='button' data-dismiss='alert'
|
||||||
span aria-hidden='true' ×
|
span aria-hidden='true' ×
|
||||||
span.sr-only Close
|
span.sr-only Close
|
||||||
= message
|
= raw(message)
|
||||||
|
|
|
@ -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
|
||||||
|
|
20
db/migrate/20151009204428_create_versions.rb
Normal file
20
db/migrate/20151009204428_create_versions.rb
Normal 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
|
17
db/migrate/20151014121823_create_version_associations.rb
Normal file
17
db/migrate/20151014121823_create_version_associations.rb
Normal 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
|
|
@ -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
|
24
db/schema.rb
24
db/schema.rb
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue