acts-as-taggable-on: Context-Scoped Tagging for Rails Models
A tagging plugin for Rails applications that allows for custom tagging along dynamic contexts.
At a glance
- What is it?
- A Rails engine that gives any ActiveRecord model multiple independent tag namespaces, backed by a shared Tag and Tagging table. It suits teams that need skills, interests and plain tags on the same record without a custom join table per concept.
- Who is it for?
- Adopt acts-as-taggable-on if you have more than one kind of tag on the same model and do not want a join table per kind; the context API and the ordered variant cover that case directly. Do not adopt it if you need an actively evolving dependency: the last push was on 2026-08-07, but the most recent tagged release is v5.0.0 from 2017-05-21, so master carries changes that no gem version reflects.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 54 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem: one model, several unrelated tag vocabularies
A user profile often needs tags that mean different things. Skills, interests and sports are not interchangeable, yet a single tags column or a single join table forces them into one pool. The README frames this as the gap the plugin was written to close: the earlier Acts as Taggable on Steroids tied functionality to the keyword tags, so a social network could not separate skills from interests. acts-as-taggable-on instead lets a model declare an arbitrary number of tag contexts, each with its own list, and each usable alone or in combination. The intended audience is a Rails developer who already has ActiveRecord models and wants tagging to behave like a first-class association rather than a text column parsed at render time. It is not a search engine, not a taxonomy service, and it does not do faceted query planning for you.
How contexts map onto Tag and Tagging rows
The mechanism is a shared vocabulary plus a polymorphic join. Tags live in one table keyed by name, and taggings connect a tag to a taggable record, carrying the context string that says which list the tag belongs to. Declaring acts_as_taggable_on :skills, :interests on a model generates per-context accessors: skill_list with add, remove and assignment, a plural skills reader, and a class-level skill_counts that returns tags with their taggings_count. Because the vocabulary table is shared, a tag named clowning is one row whether it was applied through skills or interests, which is why counts aggregate the way the README example shows: two users tagged clowning produce a taggings_count of 2. Ordering is a separate declaration. acts_as_ordered_taggable and acts_as_ordered_taggable_on preserve insertion order, so assigning east, south and later north, east, south, west reads back as north, east, south, west. If you need the sequence in which tags were applied, you have to opt into the ordered variant; the default does not promise it.
Installing the gem and tagging a first record
Add the gem to the Gemfile and bundle. The README gives the gem name as acts-as-taggable-on, and the repository ships an acts-as-taggable-on.gemspec alongside it.
gem 'acts-as-taggable-on'Then install the engine migrations and run them. The README notes that the add_tenant_to_taggings migration is optional and can be discarded safely if you do not need multi-tenancy, so read the generated files before migrating.
rake acts_as_taggable_on_engine:install:migrations
rake db:migrateWith the schema in place, declare contexts on the model. The README's example uses a User with both the default tags context and two named ones.
class User < ActiveRecord::Base
acts_as_taggable_on :tags
acts_as_taggable_on :skills, :interests
endAdding and removing is done through the generated list object, and the change is only persisted when you save. Note the two calling styles: separate arguments for individual tags, or a single string with parse: true, which splits on the configured delimiter (comma by default).
@user = User.new(:name => "Bobby")
@user.tag_list.add("awesome")
@user.skill_list.add("joking, clowning", parse: true)
@user.saveAfter the save, @user.skills returns Tag records for that context. Direct assignment such as @user.tag_list = "awesome, slick, hefty" replaces the existing list rather than appending, which the README flags explicitly.
Where it breaks: assignment semantics, MySQL collation and stale releases
Three constraints deserve attention before you commit. First, assignment is destructive. Setting tag_list to a string removes tags that were there before, and the README warns to use it with attention; a controller that binds a form field straight to tag_list will silently drop tags the form did not render. Second, MySQL users face a special-character problem the README links as issue 623. Two remedies are documented: set ActsAsTaggableOn.force_binary_collation = true in an initializer, or run the rake task acts_as_taggable_on_engine:tag_names:collate_bin. Both are opt-in, so a MySQL deployment that ignores them keeps whatever collation the column already had. Third, version drift. The most recent release listed is v5.0.0 from 2017-05-21, while the last push to the repository was on 2026-08-07. Anyone pinning a gem version is not getting the current master tree, and the README's upgrading section is the only guidance offered for crossing that gap. This is also the wrong tool if you need ranked relevance, stemming or phrase queries; a dedicated search index handles those, and tagging is a vocabulary problem, not a retrieval one.
Ownership, parsers and dirty tracking
Beyond the basic list API, the README documents three features that change how you model data. Tag ownership lets a tag belong to a specific owner, with separate sections for adding and removing owned tags, which matters when users may only edit their own labels. Tag parsers let you replace the default comma splitting when input arrives in another shape. Dirty tracking reports tag changes on the record, so you can react to a modified list without diffing it yourself. Tag cloud calculations are also covered. The trade-off is surface area: each of these is configured through the same engine, and the README does not present a single consolidated options reference, so you end up reading the relevant section for each feature rather than one table. For a small app that only needs a flat tags list, that is more mechanism than the problem requires.
acts-as-taggable-on compared with hand-rolled associations
The obvious alternative is not another gem but the Rails primitives you already have: a Tag model, a polymorphic Tagging model, and has_many :through on each taggable class. That approach gives you total control over scopes, validations and counter caches, and it has no upgrade path to worry about because you wrote it. The difference in approach is where the context concept lives. With hand-rolled associations you decide per model whether skills and interests share a table or get separate ones, and you write the context filtering yourself. acts-as-taggable-on fixes that decision in the engine: one shared tag vocabulary, one tagging table, and a context column that partitions it. You get the list API, counts, ownership and parsers without writing them, and in exchange you accept the engine's migration set and its release cadence. The repository's docker-compose.yml shows postgres:10 and mysql:8 services with the acts_as_taggable_on database, which tells you the maintainers test against both engines, but that is a statement about the test setup, not a guarantee about your version combination.
Editorial conclusion
Adopt acts-as-taggable-on if you have more than one kind of tag on the same model and do not want a join table per kind; the context API and the ordered variant cover that case directly. Do not adopt it if you need an actively evolving dependency: the last push was on 2026-08-07, but the most recent tagged release is v5.0.0 from 2017-05-21, so master carries changes that no gem version reflects. Before writing code, verify two things on your own stack: that the generated migrations run cleanly on your database, and that your Rails and Ruby versions appear in the compatibility list in the README. MySQL users should also decide up front whether to set force_binary_collation.
Frequently asked questions
What does acts-as-taggable-on do that a plain tags column does not?
It lets a single model declare several independent tag contexts, so skills, interests and tags each get their own list, accessors and counts while sharing one tag vocabulary table. A plain column gives you one undifferentiated pool of text.
How do I install acts-as-taggable-on in a Rails app?
Add gem 'acts-as-taggable-on' to the Gemfile and bundle, then run rake acts_as_taggable_on_engine:install:migrations followed by rake db:migrate. The README notes the add_tenant_to_taggings migration is optional and can be discarded if you do not need multi-tenancy.
Does acts-as-taggable-on preserve the order in which tags were added?
Only if you use acts_as_ordered_taggable or acts_as_ordered_taggable_on. The README's ordered example assigns east, south and later north, east, south, west, and reads the list back in that order after a reload.
What should MySQL users watch out for with acts-as-taggable-on?
The README documents a special-character problem, issue 623, and offers two fixes: set ActsAsTaggableOn.force_binary_collation = true in an initializer, or run the rake task acts_as_taggable_on_engine:tag_names:collate_bin.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mbleigh-acts-as-taggable-on)