[Ruby] Add tags to Rails. uses acts-as-taggable-on

3 minute read

Overview

I added the tag function using gem acts-as-taggable-on with Rails. The function I added is a tag function that allows you to prepare existing tags (in seed files) from new posts and select multiple tags from there. The image below.  Screenshot 2020-07-16 22.58.40.png

Environment

Ruby 2.5.7 Rails 5.2.4.2 Design using Bootstrap

Implementation

① Installation

Gemfile.


gem'acts-as-taggable-on','~> 6.0'

Terminal.


$ bundle install

② Create table

Terminal.


$ rails acts_as_taggable_on_engine:install:migrations

$ rails db:migrate

③ Addition to the model and controller

app/models/style.rb


class Style <ApplicationRecord
    acts_as_taggable # Added
end

For index, the tag list and what is tagged when the tag is pressed are displayed.

app/controllers/styles_controller.rb


def index
    @tags = ActsAsTaggableOn::Tag.all
# List tags
    if params[:tag]
      @styles = Style.tagged_with(params[:tag])
  #Show what is missing when searching for tags
    else
      @styles = Style.all
    end

def new
    @style = Style.new
    @tags = ActsAsTaggableOn::Tag.all
end

def show
    @style = Style.find(params[:id])
end

def create
    @style = Style.new(style_params)
    @style.user_id = current_user.id
    if @style.save
      flash[:notice] = "Style registered"
      redirect_to style_path(@style.id)
    else
      @tags = ActsAsTaggableOn::Tag.all
      render :new
   end
end
# update and destroy have similar shapes, so I will omit them.

private

def style_params
      params.require(:style).permit(:name, :user_id, :image, tag_list: [])
  # tag_list: [] added
end

end

④ Add to seed file This time, we will use the seed file because we will prepare existing tags.

db/seeds.rb


# Link with tag (described in %w())
array = %w (Cute Natural Elegant Mode Women's Mash Men's Mash Short Bob Inner Winding Bob Short Layer Long Layer Layer Women's Harvest Men's Harvest Men's Cut Men's Two-block Women's Two-block Mohican Men's Business Girls Boys Students Mrs. Barrejuge Gradient Color Celebrities Braid Wedding Ceremony Ceremony Kimono Party Casual Makeup Cute Makeup Mode Makeup Natural Makeup Elegant Makeup Ceremony Men's Wolf Women's Wolf Gradient Bob Outer Hanebob Front Drop Down Sporty Gray Hair Inner Color Earring Color Men's Perm Women's Perm Men's Mesh Men's Color)
array.each{ |tag|
  tag_list = ActsAsTaggableOn::Tag.new
  tag_list.name = tag
  tag_list.save
}

Terminal.


$ rails db:seed

⑤ Described in view

  • index.html.erb

<div class="col-xs-12">
   <% @tags.each do |tag| %>
      <%= link_to "#{tag.name}(#{tag.taggings_count})", tag_path(tag.name), class: "label label-default" %>
   <% end %>
</div>
  • new.html.erb
<%= form_for @style do |f| %>
  <div class="col-xs-12">
・・・・・・・
    <label class="col-sm-12">Tag</label>
      <div class="col-sm-12">
        <% @tags.each do |tag| %>
          <%= f.check_box :tag_list, {multiple: true }, "#{tag.name}", nil %>
          <%= f.label "#{tag.name}(#{tag.taggings_count})", class: "label label-default" %>
        <% end %>
      </div>

      <div class="col-sm-12 text-right">
        <%= f.submit "New", class: "btn btn-danger" %>
      </div>
   </div>
  </div>
<% end %>
  • show.html.erb
<label class="col-sm-12 my-top">
   <%= raw(@style.tag_list.map {|t| link_to t, tag_path(t), class: "label label-default" }.join('')) %>
</label>

Now you have the following feeling.

  • new.html.erb  Screenshot 2020-07-16 22.58.40.png

  • index.html.erb Screenshots 2020-07-16 23.57.32.png

In tagged_with(params[:tag]) of index, tags are narrowed down. Click the tag to display the data linked to the tag. #{tag.name} displays the tag name. #{tag.taggings_count} displays the number of registered tags. This completes the implementation.

Supplement

When deploying to the production environment, I got an error in acts-as-taggable-on. If you get an error, I hope you can refer to it. I need to modify the tag table,

db/migrate/..._acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb


t.references :tag, foreign_key: {to_table: ActsAsTaggableOn.tags_table}

Despite setting the above foreign key,

db/migrate/..._add_missing_unique_indices.acts_as_taggable_on_engine.rb


remove_index ActsAsTaggableOn.taggings_table, :tag_id if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id)

It seems like I’m trying to drop the index without deleting the foreign key.

So when I made it like this, it worked.

db/migrate/..._add_missing_unique_indices.acts_as_taggable_on_engine.rb


# This migration comes from acts_as_taggable_on_engine (originally 2)
if ActiveRecord.gem_version >= Gem::Version.new('5.0')
  class AddMissingUniqueIndices <ActiveRecord::Migration[4.2]; end
else
  class AddMissingUniqueIndices <ActiveRecord::Migration; end
end
AddMissingUniqueIndices.class_eval do
  def self.up
    add_index ActsAsTaggableOn.tags_table, :name, unique: true

# remove_index ActsAsTaggableOn.taggings_table, :tag_id if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id)
# Comment out the above
    if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id) # add
      remove_foreign_key :taggings, :tags #add
      remove_index ActsAsTaggableOn.taggings_table, :tag_id # added
    end
    remove_index ActsAsTaggableOn.taggings_table, name:'taggings_taggable_context_idx'add_index ActsAsTaggableOn.taggings_table,
               [:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type],
               unique: true, name:'taggings_idx'
   end

   def self.down
     remove_index ActsAsTaggableOn.tags_table, :name

     remove_index ActsAsTaggableOn.taggings_table, name:'taggings_idx'

     add_index ActsAsTaggableOn.taggings_table, :tag_id unless index_exists?(ActsAsTaggableOn.taggings_table, :tag_id)
     add_index ActsAsTaggableOn.taggings_table, [:taggable_id, :taggable_type, :context], name:'taggings_taggable_context_idx'
   end
end

Here, I have referred to the following. https://teratail.com/questions/224720

In the development environment, I got impatient because an error occurred in the gem when there was no problem… I’m glad if you can use it as a reference.