Class: Moderate::Flag

Inherits:
ApplicationRecord show all
Defined in:
lib/moderate/models/flag.rb

Overview

A system/auto-filter flag: the record an adapter (or a manual action) leaves behind when content is flagged for review rather than rejected outright.

Flags are what ‘:flag`-mode filtering produces AFTER COMMIT — the write succeeds, then a Flag lands in the queue. This is intentional and load-bearing: a flag must NEVER be created inside a validator/transaction, because a validator is supposed to be side-effect-free and a Flag written inside a transaction that later rolls back would silently vanish (you’d “moderate” content that was never saved). The Filterable concern enforces the after_commit timing; this model is just the record + the queue + the “content flagged” notification.

The same ‘pending` scope serves BOTH a human admin queue and an automated consumer (e.g. a job that auto-actions high-confidence flags), so the gem doesn’t presume a human is the only reviewer.

Constant Summary collapse

STATUSES =
%w[pending actioned dismissed].freeze
SOURCES =

Built-in/generic source names. Host-registered adapter names are also valid sources (see ‘.sources` below) because `Moderate.classify` stamps the adapter name onto the Result when the adapter does not set one explicitly. This is why a host can register `:openai` or `:image` and see that exact name in the queue.

%w[text_filter image_filter external_classifier manual].freeze
MODES =

What the flag WOULD do. ‘:flag` allowed the write and queued it; `:block` rejected the write (a block-mode trip can also be recorded as a flag for the audit trail). Validated by the model (inclusion), not a DB constraint.

%w[flag block].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.flag!(flaggable:, field:, owner:, source:, mode:, excerpt:, categories:, scores:, context:) ⇒ Object

The single entry point the Filterable concern uses to file a flag. Centralizes coercion (categories → Array, scores/context → Hash) so callers can hand us whatever shape a Moderate::Result exposed without each one re-normalizing. ‘context` is freeform JSON for audit (which policy fired, the raw classifier payload, etc.) — never relied on by the gem’s own logic.



74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/moderate/models/flag.rb', line 74

def self.flag!(flaggable:, field:, owner:, source:, mode:, excerpt:, categories:, scores:, context:)
  create!(
    flaggable: flaggable,
    field: field,
    owner: owner,
    source: source,
    mode: mode,
    excerpt: excerpt,
    categories: Array(categories),
    scores: scores.to_h,
    context: context.to_h
  )
end

.sourcesObject



88
89
90
# File 'lib/moderate/models/flag.rb', line 88

def self.sources
  (SOURCES + Moderate.config.adapters.keys.map(&:to_s)).uniq
end

Instance Method Details

#closed?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/moderate/models/flag.rb', line 96

def closed?
  status.in?(%w[actioned dismissed])
end

#flaggable_labelObject

A label for the flagged thing in the queue. Asks the flaggable for its own ‘moderation_label` (Moderate::Reportable interface); falls back to a generic “Type id” string for content that doesn’t implement it.



103
104
105
106
107
# File 'lib/moderate/models/flag.rb', line 103

def flaggable_label
  return flaggable.moderation_label if flaggable.respond_to?(:moderation_label)

  "#{flaggable_type} #{flaggable_id}"
end

#pending?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/moderate/models/flag.rb', line 92

def pending?
  status == "pending"
end