Class: TagsInput

Inherits:
TomSelectInput
  • Object
show all
Defined in:
app/inputs/tags_input.rb

Overview

Custom SimpleForm input for centralized tag selection

This input provides a TomSelect-powered multiselect that:

  • Loads tags on demand from Crm::TagsController#autocomplete
  • Allows creating new tags on the fly
  • Works with the Taggable concern's tags= setter

Only the currently selected tags are rendered as elements; the rest
arrive over the wire as the user types. Embedding the whole ~5k tag table added
~9.6k option nodes to a page, and because each TomSelect init forces a
synchronous full-document layout, that taxed every other select on the page —
a 16-option dropdown measured 479ms. Publications' edit form spent ~8.7s in
TomSelect init; selected-only brings it to ~150ms.

Usage in forms:
<%= f.input :tags, as: :tags %>
<%= f.input :tags, as: :tags, placeholder: 'Select or create tags...' %>
<%= f.input :tags, as: :tags, create: false %> # Disable new tag creation
<%= f.input :tags, as: :tags, taggable_type: 'Image' %> # only tags applied to Images
<%= f.input :tags, as: :tags, exclude_tags: Image::POPULAR_TAGS %>

Instance Method Summary collapse

Methods inherited from TomSelectInput

#input_html_classes

Instance Method Details

#collectionObject

Only the selected tags are rendered inline; the rest are fetched on demand from
Crm::TagsController#autocomplete. Values are plain tag names because
Taggable#tags= takes names (and Taggable#tags already returns names).



59
60
61
62
63
64
# File 'app/inputs/tags_input.rb', line 59

def collection
  # If a custom collection is provided, use it
  return options[:collection] if options[:collection].present?

  Array(selected_value || []).compact_blank.map { |tag_name| [tag_name.to_s, tag_name.to_s] }.uniq
end

#input(wrapper_options = nil) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'app/inputs/tags_input.rb', line 24

def input(wrapper_options = nil)
  # Consume the input-specific options before `super` — SimpleForm forwards
  # anything it doesn't recognise down to the collection helper, and the repo
  # pattern (Redactor4Input, TomSelectInput) is to delete custom keys here.
  @taggable_type = options.delete(:taggable_type).presence
  @exclude_tags = Array(options.delete(:exclude_tags)).compact_blank

  # Enable multiple selection by default for tags
  input_html_options[:multiple] = true

  # Enable creation of new tags by default (can be overridden with create: false)
  options[:create] = true unless options.key?(:create) && options[:create] == false

  # Set default placeholder
  options[:placeholder] ||= 'Select or create tags...'

  # Add tag-specific data attributes
  input_html_options[:data] ||= {}
  input_html_options[:data]['tom-select-allow-empty-option-value'] = true

  # Remote lookup. An explicit :collection opts out entirely (the caller supplied
  # its own fixed list), so don't point that at the endpoint.
  if options[:collection].blank?
    input_html_options[:data]['tom-select-suggest-url-value'] = template.autocomplete_tags_path(lookup_params)
    input_html_options[:data]['tom-select-min-chars-value'] = 1
    # Populate the dropdown on focus so tags stay browsable without typing.
    options[:preload] = true unless options.key?(:preload)
  end

  super
end