Tag parsing seems simple until you handle real user input.
Let's explore how NoFlyList's transformers handle messy tag data submitted.
Basic Setup
rails generate no_fly_list:transformer
Default transformer:
module ApplicationTagTransformer
module_function
def parse_tags(tags)
if tags.is_a?(Array)
tags
else
tags.split(separator).map(&:strip).compact
end
end
def recreate_string(tags)
tags.join(separator)
end
def separator
','
end
end
Real-World Examples
Hashtag Transformer
module HashtagTransformer
module_function
def parse_tags(tags)
return tags if tags.is_a?(Array)
tags.scan(/#[\w-]+/).map { |tag| tag.delete('#') }
end
def recreate_string(tags)
tags.map { |tag| "##{tag}" }.join(' ')
end
end
class Post < ApplicationRecord
include NoFlyList::TaggableRecord
has_tags :hashtags, transformer: HashtagTransformer
end
post = Post.new(content: "Check out #rails #ruby #webdev")
post.hashtags_list = post.content # Extracts: ["rails", "ruby", "webdev"]
Multi-Language Transformer
module MultiLangTransformer
module_function
def parse_tags(tags)
return tags if tags.is_a?(Array)
tags.split('|').map do |tag_pair|
lang, tag = tag_pair.split(':').map(&:strip)
"#{lang}:#{tag}"
end
end
def recreate_string(tags)
tags.join(' | ')
end
end
class Article < ApplicationRecord
has_tags :keywords, transformer: MultiLangTransformer
end
article.keywords_list = "en:ruby | es:rubí | fr:rubis"
Hierarchical Tag Transformer
module CategoryTransformer
module_function
def parse_tags(tags)
return tags if tags.is_a?(Array)
tags.split('>').map(&:strip)
end
def recreate_string(tags)
tags.join(' > ')
end
end
class Product < ApplicationRecord
has_tags :categories, transformer: CategoryTransformer
end
product.categories_list = "Electronics > Computers > Laptops"
Custom Normalization
module NormalizedTransformer
module_function
def parse_tags(tags)
tags = tags.split(',') unless tags.is_a?(Array)
tags.map do |tag|
tag.strip
.downcase
.gsub(/[^a-z0-9\s-]/, '') # Remove special chars
.gsub(/\s+/, '-') # Spaces to hyphens
end.uniq.compact
end
def recreate_string(tags)
tags.join(', ')
end
end
class Photo < ApplicationRecord
has_tags :labels, transformer: NormalizedTransformer
end
photo.labels_list = "Nature Photos, WILDLIFE shots, Outdoor-Photography"
# Transforms to: ["nature-photos", "wildlife-shots", "outdoor-photography"]
Context-Specific Transformers
Mix transformers based on tag context:
class Article < ApplicationRecord
include NoFlyList::TaggableRecord
has_tags :categories, transformer: CategoryTransformer
has_tags :hashtags, transformer: HashtagTransformer
has_tags :keywords, transformer: MultiLangTransformer
end
Testing Transformers
class TransformerTest < ActiveSupport::TestCase
test "hashtag parsing" do
input = "#ruby #rails doing #testing"
expected = ["ruby", "rails", "testing"]
assert_equal expected, HashtagTransformer.parse_tags(input)
end
test "hierarchical parsing" do
input = "Tech > Software > Tools"
expected = ["Tech", "Software", "Tools"]
assert_equal expected, CategoryTransformer.parse_tags(input)
end
end
Remember: Transformers are your first line of defense against messy tag data. Like TSA agents, they ensure only properly formatted tags make it through to your system.
Top comments (0)