class LoggableActivity::Activity

Represents one action in the activity log.

Public Class Methods

activities_for_actor(actor, limit = 20, params = { offset: 0 }) click to toggle source

Returns a list of activities for a given actor.

# File lib/loggable_activity/activity.rb, line 214
def self.activities_for_actor(actor, limit = 20, params = { offset: 0 })
  LoggableActivity::Activity.latest(limit, params).where(actor:)
end
last(limit = 1) click to toggle source

Returns the last activity.

# File lib/loggable_activity/activity.rb, line 230
def self.last(limit = 1)
  return latest(1).first if limit == 1

  latest(limit)
end
latest(limit = 20, params = { offset: 0 }) click to toggle source

Returns a list of activities ordered by creation date.

# File lib/loggable_activity/activity.rb, line 219
def self.latest(limit = 20, params = { offset: 0 })
  offset = params[:offset] || 0
  LoggableActivity::Activity
    .all
    .order(created_at: :desc)
    .includes(:payloads)
    .offset(offset)
    .limit(limit)
end

Public Instance Methods

actor_display_name() click to toggle source

Returns the display name for a actor. what method to use if defined in ‘/config/loggable_activity.yaml’

Example:

@activity.actor_display_name

Returns:

"Elvis Presley"
# File lib/loggable_activity/activity.rb, line 207
def actor_display_name
  return I18n.t('loggable.activity.deleted') if encrypted_actor_display_name.nil?

  LoggableActivity::Encryption.decrypt(encrypted_actor_display_name, actor_key)
end
attrs() click to toggle source

Returns a list of attributes of the activity includig the indliced relations. The included relations are devined in the ‘config/loggable_activity.yaml’ file. The attributes are packed in a way that they can be used to display the activity in the UI.

Example:

@activity.attrs

Returns:

 [
   {
     record_class: "User",
     payload_type: "primary_payload",
     attrs: {
       "first_name" => "David",
       "last_name" => "Bowie",
       "age" => "69",
       "email" => "david@example.com",
       "user_type" => "Patient"
     }
   },
   {
     record_class: "Demo::UserProfile",
     payload_type: "current_association",
     attrs: {
       "sex" => "Male",
       "religion" => "Agnostic"
     }
   },
   {
     record_class: "Demo::Address",
     payload_type: "current_association",
     attrs: {
       "street" => "Eiffel Tower",
       "city" => "Paris",
       "country" => "France",
       "postal_code" => "75007"
     }
   },
   {
     record_class: "Demo::Club",
     payload_type: "current_association",
     attrs: {
       "name" => "Mystic Fusion Lounge"
     }
   }
]
# File lib/loggable_activity/activity.rb, line 68
def attrs
  ordered_payloads.map do |payload|
    {
      record_class: payload.record_type,
      payload_type: payload.payload_type,
      attrs: payload.attrs
    }
  end
end
primary_payload_attrs() click to toggle source

Returns the attributes for the primary payload, without the relations.

Example:

@activity.primary_payload_attrs

Returns:

{
    "first_name" => "David",
    "last_name" => "Bowie",
          "age" => "69",
        "email" => "david@example.com",
    "user_type" => "Patient"
}
# File lib/loggable_activity/activity.rb, line 154
def primary_payload_attrs
  primary_payload ? primary_payload.attrs : {}
end
record_display_name() click to toggle source

Returns the display name for a record. what method to use if defined in ‘/config/loggable_activity.yaml’

Example:

@activity.record_display_name

Returns:

"David Bowie"
# File lib/loggable_activity/activity.rb, line 192
def record_display_name
  return I18n.t('loggable.activity.deleted') if encrypted_record_display_name.nil?

  LoggableActivity::Encryption.decrypt(encrypted_record_display_name, record_key)
end
relations_attrs() click to toggle source

Returns the attributes for the relations.

Example:

@activity.relations_attrs

Returns:

[
  {
    record_class: "Demo::Address",
    # Current association payload type
    payload_type: "current_association",
    # Current attributes for Demo::Address
    attrs: {
      "street" => "The Palace of Versailles",
      "city" => "Versailles",
      "country" => "France",
      "postal_code" => "78000"
    }
  }
]
# File lib/loggable_activity/activity.rb, line 179
def relations_attrs
  attrs.filter { |p| p[:payload_type] == 'current_association' }
end
update_activity_attrs() click to toggle source

Returns the attributes of an upddate activity.

Example:

@activity.update_activity_attrs

Returns:

{
  # Update attributes for Demo::Club
  update_attrs: {
    record_class: "Demo::Club",
    attrs: [
      {
        "name" => {
          # Previous name
          from: "Electric Oasis Club",
          # New name
          to: "Electric Oasis Club nr 5"
        }
      }
    ]
  },
  # Updated relations attributes
  updated_relations_attrs: [
    {
      record_class: "Demo::Address",
      previous_attrs: {
        # Record class
        record_class: "Demo::Address",
        # Previous association payload type
        payload_type: "previous_association",
        # Previous attributes for Demo::Address
        attrs: {
          "street" => "Ice Hotel, Marknadsvägen 63",
          "city" => "Jukkasjärvi",
          "country" => "Sweden",
          "postal_code" => "981 91"
        }
      },
      current_attrs: {
        record_class: "Demo::Address",
        # Current association payload type
        payload_type: "current_association",
        # Current attributes for Demo::Address
        attrs: {
          "street" => "The Palace of Versailles",
          "city" => "Versailles",
          "country" => "France",
          "postal_code" => "78000"
        }
      }
    }
  ]
}
# File lib/loggable_activity/activity.rb, line 132
def update_activity_attrs
  {
    update_attrs:,
    updated_relations_attrs:
  }
end

Private Instance Methods

actor_key() click to toggle source
# File lib/loggable_activity/activity.rb, line 276
def actor_key
  return nil if actor.nil?

  LoggableActivity::EncryptionKey.for_record(actor)&.key
end
must_have_at_least_one_payload() click to toggle source
# File lib/loggable_activity/activity.rb, line 282
def must_have_at_least_one_payload
  errors.add(:payloads, 'must have at least one payload') if payloads.empty?
end
ordered_payloads() click to toggle source
# File lib/loggable_activity/activity.rb, line 266
def ordered_payloads
  payloads.order(:payload_type)
end
previous_associations_attrs() click to toggle source
# File lib/loggable_activity/activity.rb, line 262
def previous_associations_attrs
  attrs.select { |p| p[:payload_type] == 'previous_association' }
end
primary_payload() click to toggle source
# File lib/loggable_activity/activity.rb, line 246
def primary_payload
  ordered_payloads.find { |p| p.payload_type == 'primary_payload' }
end
record_key() click to toggle source
# File lib/loggable_activity/activity.rb, line 270
def record_key
  return nil if record.nil?

  LoggableActivity::EncryptionKey.for_record(record)&.key
end
update_attrs() click to toggle source
# File lib/loggable_activity/activity.rb, line 238
def update_attrs
  update_payload_attrs = attrs.find { |p| p[:payload_type] == 'update_payload' }
  return nil unless update_payload_attrs

  update_payload_attrs.delete(:payload_type)
  update_payload_attrs
end
updated_relations_attrs() click to toggle source
# File lib/loggable_activity/activity.rb, line 250
def updated_relations_attrs
  grouped_associations = attrs.group_by { |p| p[:record_class] }

  grouped_associations.map do |record_class, payloads|
    previous_attrs = payloads.find { |p| p[:payload_type] == 'previous_association' }
    current_attrs = payloads.find { |p| p[:payload_type] == 'current_association' }
    next if previous_attrs.nil? && current_attrs.nil?

    { record_class:, previous_attrs:, current_attrs: }
  end.compact
end