Migrate tags in Rails to PostgreSQL array from ActsAsTaggableOn
ActsAsTaggableOn is a swiss army knife solution if you need to add tags to your ActiveRecord model.
Just by adding one gem to your Gemfile and
acts_as_taggable to the model you get everything you need: adding tags, searching for a model by tag, getting top tags, etc. However, sometimes you don't need all these.
In our project, we used
acts_as_taggable to store tags for
Note model. Then we displayed a list of notes on several pages with assigned tags and had autocompleted input for tags on
Note form. Everything worked well, but since we use PostgreSQL, I decided to store tags as an array in Note model.
First of all, I added
tags Array<String> column to
Note, after this migrated actsastaggable tags to
notes table with migration.
class MigrateNoteTags < ActiveRecord::Migration[5.2] def change execute <<-SQL UPDATE notes SET tags = grouped_taggings.tags_array FROM ( SELECT taggings.taggable_id, ARRAY_AGG ( tags.NAME ) tags_array FROM taggings LEFT JOIN tags ON taggings.tag_id = tags.ID WHERE taggable_type = 'Note' GROUP BY taggings.taggable_id ) AS grouped_taggings WHERE notes.ID = grouped_taggings.taggable_id SQL end end
To have backward compatibility, I added
def tag_list tags.join(', ') end
The last thing is to add the ability to search for tags. Since there about 500k records in the Notes table, I decided to create an SQL view:
CREATE OR REPLACE VIEW note_tags AS SELECT UNNEST ( tags ) AS name, COUNT ( * ) AS taggings_count FROM notes GROUP BY name
That's it! It takes from 100ms to 150ms to search for tags in this view, which is fine for me.
If you have more significant data sets, then the best would be to create
tags table and add triggers to
notes table that will update
tags on INSERT/UPDATE/DELETE.