Module: Labimotion::AiKlassValidator

Defined in:
lib/labimotion/libs/ai_klass_validator.rb

Overview

The checks that must happen BEFORE a template is generated.

Generation moved to a background job, and the cheap objections — this name is taken, this ontology term already has a template — used to live inside the create helpers, which now run inside that job. So the user spent a provider call and 15-90s of waiting only to be told the label was already in use, which was knowable before a single token was spent. Worse, the answer arrived as a notification long after the dialog that could have fixed it had closed.

These are only the objections that can be settled by a lookup. Anything the model decides at create! stays there: this is a courtesy gate, not a second source of truth, and the create still validates for real.

Class Method Summary collapse

Class Method Details

.dataset_error(params) ⇒ Object



65
66
67
68
69
70
71
72
# File 'lib/labimotion/libs/ai_klass_validator.rb', line 65

def self.dataset_error(params)
  term = params[:ols_term_id].to_s.split('|').first.to_s.strip
  return 'An ontology term (CHMO) is required.' if term.blank?

  return unless Labimotion::DatasetKlass.where(deleted_at: nil).exists?(ols_term_id: term)

  "A dataset template already exists for #{term}. Edit it in the designer instead."
end

.element_error(params) ⇒ Object

Mirrors ElementKlass's validates :name, uniqueness: — scoped to rows that are not soft-deleted, so a deleted template does not block the name it no longer holds.



40
41
42
43
44
45
46
47
48
# File 'lib/labimotion/libs/ai_klass_validator.rb', line 40

def self.element_error(params)
  name = params[:name].to_s.strip
  return 'A name is required.' if name.blank?
  return 'A label is required.' if params[:label].to_s.strip.blank?

  return unless Labimotion::ElementKlass.where(deleted_at: nil).exists?(name: name)

  "An element named [#{name}] already exists."
end

.error_for(kind:, params:, element_klass: nil) ⇒ String?

Returns the objection, or nil when there is none.

Returns:

  • (String, nil)

    the objection, or nil when there is none



19
20
21
22
23
24
25
26
27
28
# File 'lib/labimotion/libs/ai_klass_validator.rb', line 19

def self.error_for(kind:, params:, element_klass: nil)
  files = file_error(params)
  return files if files

  case kind.to_s
  when 'element' then element_error(params)
  when 'segment' then segment_error(params, element_klass)
  when 'dataset' then dataset_error(params)
  end
end

.file_error(params) ⇒ Object



30
31
32
33
34
35
# File 'lib/labimotion/libs/ai_klass_validator.rb', line 30

def self.file_error(params)
  count = Array(params[:files]).size
  return nil if count <= Labimotion::AiTemplate::MAX_FILES

  "Too many files (max #{Labimotion::AiTemplate::MAX_FILES})."
end

.segment_error(params, element_klass) ⇒ Object

Mirrors SegmentKlass's validates :label, uniqueness: { scope: :element_klass_id }. The label only has to be unique WITHIN its parent element, which is why the parent has to be known before this can be answered at all.



53
54
55
56
57
58
59
60
61
62
63
# File 'lib/labimotion/libs/ai_klass_validator.rb', line 53

def self.segment_error(params, element_klass)
  label = params[:label].to_s.strip
  return 'A label is required.' if label.blank?
  return 'A parent element is required.' if element_klass.nil?

  taken = Labimotion::SegmentKlass.where(deleted_at: nil)
                                  .exists?(label: label, element_klass_id: element_klass.id)
  return unless taken

  "A segment template labelled [#{label}] already exists for this element."
end