class Card::Action
An action is a group of {Card::Change changes} to a single {Card card} that is recorded during an {Card::Act act}. Together, {Act acts}, {Action actions}, and {Change changes} comprise a comprehensive {Card card} history tracking system.
For example, if a given web submission changes both the name and type of a given card, that would be recorded as one {Action action} with two {Change changes}. If there are multiple cards changed, each card would have its own {Action action}, but the whole submission would still comprise just one single {Act act}.
An {Action} records:
-
the card_id of the {Card card} acted upon
-
the card_act_id of the {Card::Act act} of which the action is part
-
the action_type (create, update, or delete)
-
a boolean indicated whether the action is a draft
-
a comment (where applicable)
Constants
- TYPE_OPTIONS
these are the three possible values for
action_type
Public Class Methods
# File lib/card/action.rb, line 64 def all_viewable all_with_cards.where Query::CardQuery.viewable_sql end
# File lib/card/action.rb, line 60 def all_with_cards joins :ar_card end
cache object for actions @return [Card::Cache]
# File lib/card/action.rb, line 56 def cache Card::Cache[Action] end
retrieve action from cache if available @param id [id of Action] @return [Action, nil]
# File lib/card/action.rb, line 48 def fetch id cache.fetch id.to_s do where(id: id.to_i).take end end
Public Instance Methods
retrieve action_type
(create, update, or delete) @return [Symbol]
# File lib/card/action.rb, line 106 def action_type return :draft if draft TYPE_OPTIONS[read_attribute(:action_type)] end
assign action_type
(create, update, or delete) @param value [Symbol] @return [Integer]
# File lib/card/action.rb, line 100 def action_type= value write_attribute :action_type, TYPE_OPTIONS.index(value) end
# File lib/card/action.rb, line 157 def all_changes self.class.cache.fetch("#{id}-changes") do # using card_changes causes caching problem Card::Change.where(card_action_id: id).to_a end end
each action is associated with on and only one card @return [Card]
# File lib/card/action.rb, line 71 def card Card.fetch card_id, look_in_trash: true # I'm not sure what the rationale for the following was/is, but it was causing # problems in cases where slot attributes are overridden (eg see #wrap_data in # sources on wikirate). The problem is the format object had the set modules but # the card didn't. # # My guess is that the need for the following had something to do with errors # associated with changed types. If so, the solution probably needs to handle # including the set modules associated with the type at the time of the action # rather than including no set modules at all. # # What's more, we _definitely_ don't want to hard code special behavior for # specific types in here! # , skip_modules: true # return res unless res && res.type_id.in?([Card::FileID, Card::ImageID]) # res.include_set_modules end
action's {Change} object for given field @see interpret_field
interpret_field
for field param @return [Change]
# File lib/card/action.rb, line 138 def change field changes[interpret_field field] end
all changed values in hash form. { field1: new_value }
# File lib/card/action.rb, line 178 def changed_values @changed_values ||= changes.transform_values(&:value) end
all action {Change changes} in hash form. { field1: Change1 } @return [Hash]
# File lib/card/action.rb, line 166 def changes @changes ||= if sole? current_changes else all_changes.each_with_object({}) do |change, hash| hash[change.field.to_sym] = change end end end
@return [Hash]
# File lib/card/action.rb, line 183 def current_changes return {} unless card @current_changes ||= Card::Change::TRACKED_FIELDS.each_with_object({}) do |field, hash| hash[field.to_sym] = Card::Change.new field: field, value: card.send(field), card_action_id: id end end
remove action from action cache
# File lib/card/action.rb, line 93 def expire self.class.cache.delete id.to_s end
translate field into fieldname as referred to in database @see Change::TRACKED_FIELDS @param field [Symbol] can be :type_id, :cardtype, :db_content, :content,
:name, :trash
@return [Symbol]
# File lib/card/action.rb, line 199 def interpret_field field case field when :content then :db_content when :cardtype then :type_id else field.to_sym end end
value in form prescribed for specific field name @param value [value of {Change}] @return [Integer] for :type_id @return [String] for :name, :db_content, :content, :cardtype @return [True/False] for :trash
# File lib/card/action.rb, line 212 def interpret_value field, value case field.to_sym when :type_id value&.to_i when :cardtype Card.fetch_name(value&.to_i) else value end end
# File lib/card/action.rb, line 112 def previous_action Card::Action.where("id < ? AND card_id = ?", id, card_id).last end
most recent change to given field before this one @see interpret_field
interpret_field
for field param @return [Change]
# File lib/card/action.rb, line 145 def previous_change field return nil if action_type == :create field = interpret_field field if @previous_changes&.key?(field) @previous_changes[field] else @previous_changes ||= {} @previous_changes[field] = card.last_change_on field, before: self end end
value of field set by most recent {Change} before this one @see interpret_field
interpret_field
for field param @see interpret_field
interpret_field
for field param
# File lib/card/action.rb, line 128 def previous_value field return if action_type == :create return unless (previous_change = previous_change field) interpret_value field, previous_change.value end
# File lib/card/action.rb, line 222 def sole? all_changes.empty? && (action_type == :create || Card::Action.where(card_id: card_id).count == 1) end
value set by action's {Change} to given field @see interpret_field
interpret_field
for field param @see interpret_value
interpret_value
for return values
# File lib/card/action.rb, line 119 def value field return unless (change = change field) interpret_value field, change.value end