Class: Livechat::Message

Inherits:
ApplicationRecord show all
Defined in:
app/models/livechat/message.rb

Overview

One chat entry. Three kinds of author: the visitor, a named agent, or the system (resolve/reopen events, so a thread worked by several teammates stays legible). Agent attribution is stored as loose fields — agent_id plus a label resolved at write time — no foreign key to the host's users.

Constant Summary collapse

AUTHOR_TYPES =
%w[visitor agent system].freeze
EVENTS =
%w[resolved reopened].freeze
MAX_BODY_LENGTH =
5_000
ATTACHMENTS_SUPPORTED =

Attachments ride on Active Storage, which the host installs (it's a standard Rails feature, not a livechat table). Where it isn't present the association simply isn't declared and everything stays text-only.

defined?(ActiveStorage) ? true : false

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.attachments_supported?Boolean

Returns:

  • (Boolean)


17
# File 'app/models/livechat/message.rb', line 17

def self.attachments_supported? = ATTACHMENTS_SUPPORTED

Instance Method Details

#as_inbox_json(conversation = self.conversation) ⇒ Object

The shape the inbox renders — mirrors the thread partial. system events carry a ready localized line; visitor and agent messages carry a display name for the author header. Lives here (not in the controller) so an Action Cable broadcast can build it without a request.



87
88
89
90
91
92
93
94
95
96
97
98
# File 'app/models/livechat/message.rb', line 87

def as_inbox_json(conversation = self.conversation)
  if system?
    { id: id, author: 'system',
      text: I18n.t("livechat.events.#{event}", agent: agent_label,
                                               default: "%{agent} #{event} the conversation"),
      at: created_at.to_fs(:short) }
  else
    { id: id, author: author_type,
      name: agent? ? agent_label : conversation.display_name,
      body: body, attachments: attachments_json, at: created_at.to_fs(:short) }
  end
end

#as_widget_jsonObject



71
72
73
74
75
76
77
78
79
80
81
# File 'app/models/livechat/message.rb', line 71

def as_widget_json
  {
    id: id,
    author: author_type,
    label: public_label,
    body: system? ? nil : body,
    event: event,
    attachments: attachments_json,
    at: created_at.iso8601
  }
end

#attached_filesObject

The attached files, or an empty list where Active Storage is absent or attachments are off — callers never have to branch on support.



53
54
55
# File 'app/models/livechat/message.rb', line 53

def attached_files
  files_attached? ? files : []
end

#attachments_jsonObject

[{ id:, name:, url:, image:, size: }] — url is the gated engine route, image flags the ones the client renders inline instead of as a link.



102
103
104
105
106
107
108
109
110
111
112
113
# File 'app/models/livechat/message.rb', line 102

def attachments_json
  return [] unless files_attached?

  base = Livechat.config.mount_path.to_s.chomp('/')
  files.map do |file|
    { id: file.id,
      name: file.filename.to_s,
      url: "#{base}/attachments/#{file.id}",
      image: file.content_type.to_s.start_with?('image/'),
      size: file.byte_size }
  end
end

#files_attached?Boolean

Returns:

  • (Boolean)


57
58
59
# File 'app/models/livechat/message.rb', line 57

def files_attached?
  Livechat.attachments_enabled? && files.attached?
end

#previewObject

A one-line summary for the inbox list: the body, or a note of what was attached when a message is files-only.



63
64
65
66
67
68
69
# File 'app/models/livechat/message.rb', line 63

def preview
  return body.to_s.truncate(140) if body.present?
  return '' unless files_attached?

  names = files.map { |file| file.filename.to_s }
  names.one? ? "📎 #{names.first}" : "📎 #{names.size} files"
end

#public_labelObject

What the widget shows as the sender of an agent message — run through config.agent_display_name, so hosts control how much of the team's identity visitors see.



47
48
49
# File 'app/models/livechat/message.rb', line 47

def public_label
  agent? ? Livechat.display_name_for(agent_label) : nil
end

#read?Boolean

Returns:

  • (Boolean)


42
# File 'app/models/livechat/message.rb', line 42

def read? = read_at.present?