How to add tags in Ruby on Rails

If you want to add tags, categories, filters, and so on, to your Rails 5 models, the acts-as-taggable-on gem is the way to go. This post will help you set it up.

  1. Add it to your Gemfile:

    gem 'acts-as-taggable-on', '~> 6.0'
    
  2. Run bundle install.

  3. Install its migrations:

    rake acts_as_taggable_on_engine:install:migrations
    
  4. Run rake db:migrate.

  5. Add acts_as_taggable_on to your model. You don’t need to create a migration for your tags – acts-as-taggable-on handles that for you. You can change :tags to anything you’d like – :categories, :codes, etc.

    # post.rb
    class Post < ApplicationRecord
      acts_as_taggable_on :tags
    end
    
  6. Then, inside your controller, you’ll need to accept :tag_list (or :category_list, or :code_list, etc.) as a strong param. It’s the singular version of the word you used in your model, appended with _list.

    # posts_controller.rb
    class PostsController < ApplicationController
      # ...
    
      def post_params
        params.require(:post).permit(:title, :body, :tag_list)
      end
    end
    
  7. Now you can add the tags to a form. Sometimes, you may be able to get away with <%= f.input :tag_list %>, but I’ve had to use a slightly more complicated version in the past. Users can add multiple tags by separating them with commas:

    <!-- views/posts/_form.html.erb -->
    <%= form.label :tag_list, "Tags" %>
    <%= 
      form.text_field :tag_list, 
      value: @post.send(:tag_list).to_s, 
      placeholder: 'rails, development'
    %>
    
  8. You can search by tagged filters, as well:

    # routes.rb
    get '/tagged', to: "posts#tagged", as: :tagged
    
    # posts_controller.rb
    def tagged
      if params[:tag].present?
        @posts = Post.tagged_with(params[:tag])
      else
        @posts = Post.all
      end
    end
    
  9. And then list each post, plus the option to sort by tags in your view:

    <!-- views/posts/index.html.erb -->
    <% @posts.each do |p| %>
    <h2><%= p.title %></h2>
    <div class="tags">
      <% p.tag_list.each do |t| %>
        <%= link_to t, tagged_path(tag: t) %>
      <% end %>
    </div>
    <% end %>
    

Once you understand how it works, acts-as-taggable-on is a pretty easy gem to use. It has a lot of other features, as well, that you can learn more about on its GitHub page. Have fun tagging!

Mark @mtmdev_