Enable the admin to configure tags for selection in a dropdown, to control type and amount of tags stored
Step 1: add a migration, assuming usage of ActsAsTaggableOn
- though any Tag
model would work.
Adding :archived_at
as bonus…
# frozen_string_literal: true
class CreateTagSettings < ActiveRecord::Migration[6.1]
def change
create_table :tag_settings do |t|
t.references :tag, null: false, foreign_key: true
t.string :target_type
t.datetime :archived_at
t.timestamps
end
end
end
Step 2: Design the models
class TagSetting < ApplicationRecord
belongs_to :tag
scope :publications, -> { where(target_type: TARGET_TYPES.first).order(:id) }
scope :active, -> { where(archived_at: nil) }
attr_accessor :name
TARGET_TYPES = %w[publication].freeze # for flexibility the model name is not used
def archive!
update!(archived_at: Time.current)
end
def un_archive!
update!(archived_at: nil)
end
def active
!archived_at.present?
end
end
And the Tag
model:
class Tag < ActsAsTaggableOn::Tag
has_many :tag_settings
end
Step 3: Save, update or show the relevant tag(s):
class TagSettingsController < ApplicationController
before_action :set_tag_setting, only: %i[edit update show]
def index
@tag_settings = TagSetting.publications
end
def show; end
def new
@tag_setting = TagSetting.new
end
def create
if tag_setting_params[:name].present?
@tag = ActsAsTaggableOn::Tag.find_or_create_by!(name: tag_setting_params[:name].downcase)
@tag_setting = TagSetting.new(tag_id: @tag.id, target_type: TagSetting::TARGET_TYPES.first)
else
@tag_setting = TagSetting.new
end
respond_to do |format|
if @tag_setting.save
format.html do
redirect_to some_tag_settings_path,
notice: 'Publication tag was successfully created.'
end
else
format.html { render :new }
end
end
end
def edit; end
def update
respond_to do |format|
case tag_setting_params[:active]
when '1'
@tag_setting.un_archive!
format.html do
redirect_to some_tag_settings_path,
notice: 'Publication tag was successfully actived.'
end
when '0'
@tag_setting.archive!
format.html do
redirect_to some_tag_settings_path,
notice: 'Publication tag was successfully archived.'
end
end
end
end
private
def set_tag_setting
@tag_setting = TagSetting.find(params[:id])
end
def tag_setting_params
params.require(:tag_setting).permit(:id, :name, :type, :active)
end
end
Step 4: Enabling to add or archive a Tag, add these in a form.html.slim
.
I’ve omitted the show and index template, for brevity.
.col-4.pb-2
.card
.card-body
- if @tag_setting.new_record?
= simple_form_for [:admin, @tag_setting], url: some_tag_settings_path do |f|
= f.input :name, label: "Tag name"
= f.button :submit, "Save", class: "btn btn-sm btn-success me-2 rounded-0", data: { turbo: false }
- else
= simple_form_for [:admin, @tag_setting], url: some_tag_setting_path(@tag_setting) do |f|
= f.input :name, label: "Tag name", input_html: { disabled: true, value: ActsAsTaggableOn::Tag.find(@tag_setting.tag_id) }
= f.input :active, label: "Active", as: :boolean
= f.button :submit, "Save", class: "btn btn-sm btn-success me-2 rounded-0", data: { turbo: false }
Step 5: add this to the relevant line in routes.rb, to make all of the above available.
resources :tag_settings, only: %i[index create update new edit]
Step 6: make them available for association with the relevant Model:
- a. Add to the MODEL:
acts_as_taggable_on :document_tags
- b. Add to controller:
before_action :set_tags, only: %i[new edit update]
andprivate def set_tags @categories_collection = ActsAsTaggableOn::Tag.where(id: TagSetting.publications.active.select(:tag_id)) end
- c. Add to params in controller:
def publication_params params.require(:publication).permit(:title, ..., document_tag_list: []) end
- d. finally, enable in the MODEL form. Please note that the
value_method
is the:name
attribute, not the:id
.= f.input :document_tag_list, collection: @categories_collection, label: "Tags", \ input_html: { class: "foobar", multiple: true, value: f.object.document_tags.join(",") }, label_method: :name, value_method: :name