For more posts in this series, check out my tutorial on Devise Authentication with Rails 5.
Acts as Taggable On is one of my favorite underrated (and awkwardly named) Rails gems. There’s almost always the need to search or organize objects in a Rails application and using tags simplifies the process so much. It also saves developers new to Rails from writing out monstrous Active Record queries. acts-as-taggable-on is a true work horse, it’s been around since 2010 and has over 8 million downloads to date. Here is a quick getting started guide on using it.
What are tags and why do we use them?
- Tags help users find related information — they allow you to group one or several instances of a model together without having to create a separate category table.
- Tags help when users are not sure what they are looking for — for example, think of Amazon and its related products. Sometimes people who buy toothpaste will also buy tooth brushes. But your site will be more powerful if it can tag the items and suggest things like face wash or body cream.
- Tags allow for a broader ‘category’ label without having to make a standalone table or parent-child-relationship — This means that you can connect several tables without a million foreign keys.
- Therefore, tags help visitors remain on the site for longer — You want this, because $$$.
- There is no ‘tags’ column in the database table
- Tags acts as a ‘virtual column’ — it lives in its own table
- Find the full documentation here: https://github.com/mbleigh/acts-as-taggable-on/
How to use the Acts As Taggable Gem
Install the gem
#add the gem to your gemfile gem 'acts-as-taggable-on', '~> 6.0' #must be this version for Rails5
#install the gem bundle install
#generate the migrations to create taggings in the db rails acts_as_taggable_on_engine:install:migrations rails db:migrate
Create the model you are going to tag
rails g scaffold Restaurant name:string description:string rails db:migrate #NOTE: there is no tags column for the restaurants table
#add this line to app/models/restaurants.rb acts_as_taggable_on :tags
Use Case 1: I want to add tags to my model in the backend
rails c restaurant = Restaurant.new(name: “Lost Heaven”, description: "Yunnan food in the heart of the former french concession", tag_list: “Yunnan”, “Spicy”, “Good Cocktails”) restaurant.save
#add or remove tags restaurant.tag_list.add(“Bund”) restaurant.tag_list.remove("Bund")
#return all of the tags of a given restaurant restaurant.tag_list
#return all of the instances of a class with a specific tag Restaurant.tagged_with("spicy")
Use Case 2: As a user, I want to be able to tag a model with a specific tag, then search for all the restaurants by their tag
Step 1. Add the tags to permitted params in the controller #app/controllers/restaurants_controller.rb def restaurant_params params.require(:restaurant).permit(:name, :description, :tag_list) end
Step 2. Add the tags to the form of the site #app/views/_form.html.erb <%= f.input :tag_list %>
Step 3. Search by tag filters #app/controllers/restaurants_controller.rb
def tagged if params[:tag].present? @restaurants = Restaurant.tagged_with(params[:tag]) else @restaurants = Restaurant.all end end
#config/routes.rb get '/tagged', to: "restaurants#tagged", as: :tagged
#app/views/index.html.erb <% @restaurants.each do |r| %> <h2><%= r.name %></h2> <p><% r.tag_list.each do |tag| %> <%= link_to tag, tagged_path(tag: tag) %> <% end %></p> <% end %>
Use Case 3: As a user, I want to be able to find related restaurants based on their tags
#app/controllers/restaurants_controller.rb def show @restaurant = Restaurant.find(params[:id]) @related_restaurants = @restaurant.find_related_tags end
#app/views/restaurants/show.html.erb <h1><%= @restaurant.name %></h1> <ul> <% @related_restaurants.each do |r| %> <li><%= r.name %></li> <% end %> </ul>
Useful Acts_As_Taggable Methods
#returns most and least used tags ActsAsTaggableOn::Tag.most_used(10) ActsAsTaggableOn::Tag.least_used(10)
#force all tags to be saved as lowercase ActsAsTaggableOn.force_lowercase = true
#add tags separated by comma (default), can change to space or others ActsAsTaggableOn.delimiter = ','
Acts As Favoritor — https://github.com/jonhue/acts_as_favoritor
Acts As Votable (Likable) — https://github.com/ryanto/acts_as_votable
Do you guys find this a useful gem? Are there any other use cases of acts-as-taggable-on that I missed? Let me know below!