module RequiresApproval
Public Class Methods
included(klass)
click to toggle source
# File lib/requires_approval.rb, line 8 def self.included(klass) klass.send(:extend, ClassMethods) end
Public Instance Methods
approve_all_attributes()
click to toggle source
# File lib/requires_approval.rb, line 12 def approve_all_attributes self.approve_attributes(self.fields_requiring_approval) end
approve_attributes(*attributes)
click to toggle source
approve a list of attributes
# File lib/requires_approval.rb, line 17 def approve_attributes(*attributes) return true unless self.has_pending_changes? # validate an normalize our attributes attributes = self.check_attributes_for_approval(attributes) # make sure that all attributes are provided if we have never # been approved fields_not_being_approved = (self.fields_requiring_approval - attributes) if fields_not_being_approved.present? && self.never_approved? raise PartialApprovalForNewObject.new( "You must approve #{self.fields_requiring_approval.join(", ")} " + "for a new #{self.class.name}" ) end attributes.flatten.each do |attr| write_attribute(attr, self.latest_unapproved_version.send(attr)) end # if we have approved all requested changes, make our latest # unapproved version approved - # this is ALWAYS true for a new record even though its pending_changes # hash is forced to have values if self.is_first_version? || self.no_pending_changes? self.latest_unapproved_version.update_attribute(:is_approved, true) else # makes our latest_unapproved_version approved and # creates another unapproved version with any remaining # attributes self.create_approval_version_record end self.is_frozen = false self.save self.reload true end
deny_attributes(*attributes)
click to toggle source
# File lib/requires_approval.rb, line 59 def deny_attributes(*attributes) unless self.has_approved_version? raise DenyingNeverApprovedError.new end attributes = self.check_attributes_for_approval(attributes) attributes.flatten.each do |attr| self.latest_unapproved_version.send("#{attr}=", self.send(attr)) true end # if we have denied all changes, remove the record unless self.has_pending_changes? self.latest_unapproved_version.destroy else self.latest_unapproved_version.save end self.reload true end
has_approved_version?()
click to toggle source
have any of our versions ever been approved?
# File lib/requires_approval.rb, line 84 def has_approved_version? self.versions.count(:conditions => {:is_approved => true}) > 0 end
has_pending_changes?()
click to toggle source
have we already approved all outstanding changes?
# File lib/requires_approval.rb, line 89 def has_pending_changes? self.pending_changes.present? end
is_first_version?()
click to toggle source
are we the first version?
# File lib/requires_approval.rb, line 94 def is_first_version? !self.has_approved_version? end
no_pending_changes?()
click to toggle source
returns true if there are no changes to approve
# File lib/requires_approval.rb, line 99 def no_pending_changes? !self.has_pending_changes? end
pending_changes()
click to toggle source
the changes users have requested since the last approval
# File lib/requires_approval.rb, line 104 def pending_changes return {} if self.latest_unapproved_version.blank? ret = {} # check each field requiring approval self.fields_requiring_approval.each do |field| # if it is the same in the unapproved as in the parent table # we skip it if self.is_first_version? || self.send(field) != self.latest_unapproved_version.send(field) # otherwise we get the change set ret[field] = { # our first version is always nil, regardless of the # defaults in that table "was" => self.is_first_version? ? nil : self.send(field), "became" => self.latest_unapproved_version.send(field) } end end ret end
Protected Instance Methods
attributes_requiring_approval()
click to toggle source
the attributes that require approval
# File lib/requires_approval.rb, line 131 def attributes_requiring_approval self.attributes.select{|k,v| self.fields_requiring_approval.include?(k)} end
check_attributes_for_approval(attributes)
click to toggle source
check if our attributes are valid for approval
# File lib/requires_approval.rb, line 136 def check_attributes_for_approval(attributes) # normalize attributes attributes = Array.wrap(attributes).flatten.collect(&:to_s) # check for invalid attributes invalid_fields = (attributes - self.fields_requiring_approval) # if we have fields not requiring approval, raise an error if invalid_fields.present? raise InvalidFieldsError.new( "fields_requiring_approval don't include #{invalid_fields.join(",")}" ) end attributes end
create_approval_version_record()
click to toggle source
creates the record of an individual approval
# File lib/requires_approval.rb, line 152 def create_approval_version_record outstanding_changes = self.pending_attributes # update our old latest_unapproved_version to reflect our changes self.latest_unapproved_version.update_attributes( self.attributes_requiring_approval.merge(:is_approved => true) ) # reload so this unapproved version is out of our cache and will not # get its foreign key unassigned self.latest_unapproved_version(true) self.latest_unapproved_version = self.versions_class.new( self.attributes_requiring_approval.merge(outstanding_changes) ) end
latest_unapproved_version_with_nil_check()
click to toggle source
gets the latest unapproved version or creates a new one
# File lib/requires_approval.rb, line 168 def latest_unapproved_version_with_nil_check self.latest_unapproved_version ||= begin self.versions_class.new(self.attributes_requiring_approval) end end
never_approved?()
click to toggle source
has this record never been approved?
# File lib/requires_approval.rb, line 175 def never_approved? !self.has_approved_version? end
pending_attributes()
click to toggle source
ActiveRecord-style attribute hash for the requested changes
# File lib/requires_approval.rb, line 181 def pending_attributes ret = {} self.pending_changes.each_pair do |k, change| ret[k] = change["became"] end ret end
versions_class()
click to toggle source
the class which our versions are
# File lib/requires_approval.rb, line 190 def versions_class self.class.versions_class end