Learn how to upgrade your Rails application to allow users to dynamically add custom tags using SQLite JSON functions and Stimulus. We’ll guide you through creating an array-based tag system, enabling users to insert and save custom tags. This upgrade improves your app's searchability, flexibility, and overall user experience.
Our tags array column and collection of checkboxes already provide great usability, but I want to take it a step further by allowing users to define their own tags. To achieve this, we need to introduce some additional functionality into our application.
Replacing the Static Tags List
Instead of using a static TAGS constant, we will:
- Remove the predefined set of tags.
- Dynamically retrieve the unique tags across our entire database.
To do this efficiently, we can use built-in SQLite functionality, which I have wrapped in a model concern called ArrayColumns.
Leveraging ArrayColumns for Tag Management
The ArrayColumns concern allows us to:
- Declare which columns in our model should be treated as arrays.
- Automatically generate useful methods and scopes for handling these array-based columns.
- Build all of this functionality on top of SQLite’s json_each table-valued function.
Using json_each, we can:
- Fetch all unique tags by selecting distinct values from the array.
- Generate a tag cloud, showing how many posts contain each tag.
- Find posts that match specific tags using built-in Active Record scopes.
For example:
- Find posts with at least one tag
- Find posts containing all specified tags
- Find posts missing a specific tag
Additionally, we provide instance methods to check:
- Does this post contain a specific tag?
- Does this post have all required tags?
Integrating ArrayColumns into Our Post Model
Now that we have tag management powered by SQLite JSON functions, we can integrate it into our Post model:
- Include the ArrayColumns concern in our model.
- Declare tags as an array column instead of manually normalizing them.
- Automatically retrieve unique tags for our form checkboxes.
With this setup, our form already works using existing database tags, and users can select from previously created tags.
Expanding the Form to Allow User-Defined Tags
Next, we enhance the form so users can add custom tags dynamically.
- Use a Stimulus controller (clone_controller) to handle adding new tag inputs.
- Define a hidden template containing a blank tag input field.
- Insert new fields dynamically when users click the "Add Tag" button.
How the Stimulus Controller Works
The Stimulus controller handles the logic for inserting new tag fields:
- It clones the template input field.
- It inserts it into the DOM before the "Add" button.
- It automatically focuses the new input so users can start typing immediately.
Testing the Dynamic Tag System
Now, when editing a post:
- Users can select existing tags from checkboxes.
- They can add new tags by clicking the "Add" button and entering a custom value.
- The form submits and saves all selected and newly created tags.
For example:
- A user adds "Another", "Hello", and "Two" as new tags.
- Upon saving, those tags become available across all posts.
- Editing a different post still allows selecting previously added tags.
This system ensures tags remain flexible and user-friendly, while still maintaining a structured database schema.
Final Thoughts: A More Powerful Tagging System
- Fully dynamic tagging system—users can add custom tags without predefined limitations.
- Efficient database queries—leveraging SQLite's JSON functions ensures optimal performance.
- Improved user experience—checkboxes for existing tags and an input field for new ones provide the best of both worlds.
In the next video, we’ll explore how to enhance our URLs using virtual columns to make them more readable and self-healing.