Skip to content

Commit

Permalink
Isolate paper_trail
Browse files Browse the repository at this point in the history
  • Loading branch information
mrcasals committed Nov 17, 2017
1 parent 0967660 commit 214197b
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 3 deletions.
Expand Up @@ -11,11 +11,10 @@ class Result < Accountability::ApplicationRecord
include Decidim::HasCategory
include Decidim::HasReference
include Decidim::Comments::Commentable
include Decidim::Traceable

feature_manifest_name "accountability"

has_paper_trail

has_many :children, foreign_key: "parent_id", class_name: "Decidim::Accountability::Result", inverse_of: :parent, dependent: :destroy
belongs_to :parent, foreign_key: "parent_id", class_name: "Decidim::Accountability::Result", inverse_of: :children, optional: true, counter_cache: :children_count

Expand Down
2 changes: 1 addition & 1 deletion decidim-core/app/helpers/decidim/traceability_helper.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true

module Decidim
# A Helper to render and link to resources.
# A Helper to find and render the author of a version.
module TraceabilityHelper
# Renders the avatar and author name of the author of the last version of the given
# resource.
Expand Down
73 changes: 73 additions & 0 deletions decidim-core/app/services/decidim/traceability.rb
@@ -0,0 +1,73 @@
# frozen_string_literal: true

module Decidim
# This class wraps the logic to trace resource changes and their authorship.
# It is expected to be used with classes implementing the `Decidim::Traceable`
# concern. Version authors can be retrieved using the methods in
# `Decidim::TraceabilityHelper`.
#
# Examples:
#
# # consider MyResource implements Decidim::Traceable
# resource = Decidim::Traceability.new.create!(MyResource, author, params)
# resource.versions.count # => 1
# resource.versions.last.whodunnit # => author.to_gid.to_s
# resource.versions.last.event # => "create"
# resource = Decidim::Traceability.new.update!(resource, author, params)
# resource.versions.count # => 2
# resource.versions.last.event # => "update"
#
# This class uses the `paper_trail` gem internally, so refer to its documentation
# for further info on how to interact with versions.
class Traceability
# Calls the `create` method to the given class and sets the author of the version.
#
# klass - An ActiveRecord class that implements `Decidim::Traceable`
# author - An object that implements `to_gid` or a String
# params - a Hash
#
# Returns an instance of `klass`.
def create(klass, author, params)
PaperTrail.whodunnit(gid(author)) do
klass.create(params)
end
end

# Calls the `create!` method to the given class and sets the author of the version.
#
# klass - An ActiveRecord class that implements `Decidim::Traceable`
# author - An object that implements `to_gid` or a String
# params - a Hash
#
# Returns an instance of `klass`.
def create!(klass, author, params)
PaperTrail.whodunnit(gid(author)) do
klass.create!(params)
end
end

# Updates the `resource` with `update_attributes!` and sets the author of the version.
#
# resource - An ActiveRecord instance that implements `Decidim::Traceable`
# author - An object that implements `to_gid` or a String
# params - a Hash
#
# Returns the updated `resource`.
def update!(resource, author, params)
PaperTrail.whodunnit(gid(author)) do
resource.update_attributes!(params)
resource
end
end

private

# Calculates the GlobalID of the version author. If the object does not respond to
# `to_gid`, then it returns the object itself.
def gid(author)
return if author.blank?
return author.to_gid if author.respond_to?(:to_gid)
author
end
end
end
6 changes: 6 additions & 0 deletions decidim-core/lib/decidim/core.rb
Expand Up @@ -15,6 +15,7 @@ module Decidim
autoload :ParticipatorySpaceManifest, "decidim/participatory_space_manifest"
autoload :ResourceManifest, "decidim/resource_manifest"
autoload :Resourceable, "decidim/resourceable"
autoload :Traceable, "decidim/traceable"
autoload :Reportable, "decidim/reportable"
autoload :Authorable, "decidim/authorable"
autoload :Participable, "decidim/participable"
Expand Down Expand Up @@ -255,4 +256,9 @@ def self.menu(name, &block)
def self.view_hooks
@view_hooks ||= ViewHooks.new
end

# Public: Stores an instance of Traceability
def self.traceability
@traceability ||= Traceability.new
end
end
21 changes: 21 additions & 0 deletions decidim-core/lib/decidim/traceable.rb
@@ -0,0 +1,21 @@
# frozen_string_literal: true

require "active_support/concern"

module Decidim
# A concern that adds traceabilty capability to the given model. Including this
# allows you the keep track of changes in the model attributes and changes authorship.
#
# Example:
#
# class MyModel < ApplicationRecord
# include Decidim::Traceable
# end
module Traceable
extend ActiveSupport::Concern

included do
has_paper_trail
end
end
end
66 changes: 66 additions & 0 deletions decidim-core/spec/services/decidim/traceability_spec.rb
@@ -0,0 +1,66 @@
# frozen_string_literal: true

require "spec_helper"

describe Decidim::Traceability, versioning: true do
let!(:user) { create :user }
let(:klass) { Decidim::DummyResources::DummyResource }
let(:params) { attributes_for(:dummy_resource) }
subject { described_class.new }

describe "create" do
it "calls `create` to the class" do
expect(klass).to receive(:create).with(params)
subject.create(klass, user, params)
end

it "generates a new version for the resource" do
resource = subject.create(klass, user, params)
expect(resource.versions.count).to eq 1
expect(resource.versions.last.event).to eq "create"
end

it "sets the author of the version to the user" do
resource = subject.create(klass, user, params)
expect(resource.versions.last.whodunnit).to eq user.to_gid.to_s
end
end

describe "create!" do
it "calls `create!` to the class" do
expect(klass).to receive(:create!).with(params)
subject.create!(klass, user, params)
end

it "generates a new version for the resource" do
resource = subject.create!(klass, user, params)
expect(resource.versions.count).to eq 1
expect(resource.versions.last.event).to eq "create"
end

it "sets the author of the version to the user" do
resource = subject.create!(klass, user, params)
expect(resource.versions.last.whodunnit).to eq user.to_gid.to_s
end
end

describe "update!" do
let(:dummy_resource) { create :dummy_resource }

it "calls `update_attributes!` to the resource" do
expect(dummy_resource).to receive(:update_attributes!).with(params)
subject.update!(dummy_resource, user, params)
end

it "generates a new version for the resource" do
resource = subject.update!(dummy_resource, user, params)
expect(resource.versions.count).to eq 2
expect(resource.versions.last.event).to eq "update"
end

it "sets the author of the version to the user" do
resource = subject.update!(dummy_resource, user, params)
expect(resource.versions.last.whodunnit).to eq user.to_gid.to_s
end
end
end
1 change: 1 addition & 0 deletions decidim-dev/lib/decidim/dev/test/rspec_support/feature.rb
Expand Up @@ -41,6 +41,7 @@ class DummyResource < ApplicationRecord
include HasScope
include Decidim::Comments::Commentable
include Followable
include Traceable

feature_manifest_name "dummy"

Expand Down

0 comments on commit 214197b

Please sign in to comment.