pat/gutentag

Tag names case sensitive

rmehner opened this issue · 1 comments

Hey there,

I have kind of a strange requirement, but it makes sense for the client: tag names have to be case sensitive and a tag named Ruby is not the same as ruby.

So here's what I did:

# config/initializers/gutentag.rb

# don't normalise tag names
Gutentag.normaliser = lambda { |name| name }

# overwrite validations, so uniqueness is not case insensitive as it is the default
class TagValidations
  def self.call(klass)
    new(klass).call
  end

  def initialize(klass)
    @klass = klass
  end

  def call
    klass.validates :name, presence: true, uniqueness: true, length: {maximum: 255}
  end

  private

  attr_reader :klass
end

Gutentag.tag_validations = TagValidations

Which works fine to a certain point, but there's a nuance in MySQL. Depending on the collation of the field (which often is utf8_general_ci, which is a default in many MySQL setups I have seen), the index might be case sensitive or not. If you set a unique index, like we do at

add_index :gutentag_tags, :name, :unique => true
MySQL will treat this index as case insensitive, meaning ruby and Ruby will be the same and therefore will throw an error.

To get it working, you have to change the collation to something that is case sensitive in MySQL (there's a whole bunch of docs about that here https://dev.mysql.com/doc/refman/5.7/en/case-sensitivity.html).

In my case, I wrote this migration:

class ChangeCollationOfGutentagTags < ActiveRecord::Migration[5.2]
  def up
    execute "ALTER TABLE `gutentag_tags` CONVERT TO CHARACTER SET UTF8 COLLATE utf8_bin"
  end

  def down
    execute "ALTER TABLE `gutentag_tags` CONVERT TO CHARACTER SET UTF8 COLLATE utf8_general_ci"
  end
end

and it now works like a charm :)

I don't know if Gutentag can do anything about this (unlikely), but at least this is documented somewhere now :)

pat commented

Thanks - just noted this in the README, and released v1.1.0 👍