The answer to this question had eluded me and I couldn't find a good existing answer to it after a few Google searches. I figured it out and the answer was simple, which is always great. Hopefully this helps someone.
My problem
acts_as_taggable_on doesn't use validators to prevent excessively long tags or tags with periods in them.
One of our beta testers found that he could enter any length tag name in a new post and it would be accepted. Except that the database uses a 255 character varying length string so anything bigger will blow up the page.
Periods will screw up your tag show route if you use the name as the id (this is a common practice) since Rails routes use the period as a delimiter to infer the format (json, etc).
Solution
class Post < ActiveRecord::Base
acts_as_taggable
validates :tag_list, :length => { :maximum => 30 } # Limit to 30 tags max
validate :each_tag
private
def each_tag
for tag in tag_list
errors.add(:tag, "too long (maximum is 50 characters)") if tag.length > 50
errors.add(:tag, "can't contain a period") if tag.include? '.'
end
end
end
Failed attempts
Before I arrived at the above code I tried a couple things that didn't work.
First attempt
class Post < ActiveRecord::Base
validates_associated :taggings
end
class Tagging < ActiveRecord::Base
validates_associated :tag
end
class Tag < ActiveRecord::Base
validates :name, :length => { :maximum => 30 }
end
Besides this one needing a Tagging.rb model be created, which I didn't like, it didn't work.
Second attempt
Tag.validate :name, :length => { :maximum => 50 }
Why the solution works
tag_list exists before the model is saved. The tags don't exist at this point because the model hasn't been saved.
Thankfully tag_list is stored as a collection so you can traverse it easily and run validators on it the way you'd want to. That's why this works.
Note: If you have named your tag set something else, say for instance "bands" then it would be "band_list".