Class: Chats::Reaction

Inherits:
ApplicationRecord show all
Defined in:
lib/chats/models/reaction.rb

Overview

An emoji reaction on a message. One row per (message, reactor, emoji) โ€”the unique index makes โ€˜toggle!` race-safe. Reactors are polymorphic like every actor in this gem.

Constant Summary collapse

EMOJI_MAX_LENGTH =

Reactions are short by nature; 16 chars comfortably fits any emoji grapheme cluster (ZWJ sequences like ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ are up to ~11 chars) while making โ€œsmuggle a paragraph into a reactionโ€ impossible.

16

Class Method Summary collapse

Class Method Details

.summary_for(message) ⇒ Object

Grouped summary for rendering: [[โ€œ๐Ÿ‘โ€, 3], [โ€œ๐Ÿš—โ€, 1]] โ€” stable order so bubbles donโ€™t shuffle when counts change.



50
51
52
# File 'lib/chats/models/reaction.rb', line 50

def self.summary_for(message)
  where(message: message).group(:emoji).count.sort_by { |emoji, _count| emoji }
end

.toggle!(message:, reactor:, emoji:) ⇒ Object

Add the reaction if absent, remove it if present (the universal tap-to-toggle semantic). Returns the created reaction, or false when toggled off. Race-safe: a concurrent double-tap resolves through the unique index instead of raising.



34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/chats/models/reaction.rb', line 34

def self.toggle!(message:, reactor:, emoji:)
  existing = find_by(message: message, reactor: reactor, emoji: emoji)
  if existing
    existing.destroy!
    false
  else
    create!(message: message, reactor: reactor, emoji: emoji)
  end
rescue ActiveRecord::RecordNotUnique
  # Lost the race with an identical create โ€” treat as toggle-off.
  find_by(message: message, reactor: reactor, emoji: emoji)&.destroy!
  false
end