Ilja KO
Ilja KO

Reputation: 1616

Rails validate uniqueness for the ASCII approximation

I hope the title is not too unclear.

I am making arails app and I have a question about rails validation. Consider this code in the User,rb model file:

validates :name,
          presence: true,
          length: { maximum: 50 },
          uniqueness: { case_sensitive: false }

I am using the friendly_id gem to generate slugs for the users. I wont allow users to change their name. What I now need is to ensure that Names are unique in such a way that there will be no UUID's appended to slugs if two people have the same name converted in ascii approximation.

Current behaviour is:

User 1 signs up with a name and gets a slug like this:

name: "Jaiel" slug: "jaiel"

User 2 now does the same name but a bit different:

name: "Jàìèl" slug: "jaiel-6558c3f1-e6a1-4199-a53e-4ccc565657d4"

The problem here as you see I want such a uniqueness validation that User 2 would have been rejected because both names would generate the slug "jaiel" for their friendly_id's

I would appreciate your help on that matter

Thanks

Upvotes: 0

Views: 168

Answers (1)

Andrey Deineko
Andrey Deineko

Reputation: 52377

Take a look into ActiveSupport::Inflector.transliterate:

ActiveSupport::Inflector.transliterate('Ærøskøbing')
#=> "AEroskobing"

Also, with this type of validation you might want to go with custom validation (alongside the one you already have):

class User
  validate :unique_slug

  private

  def unique_slug
    names = self.class.all.map(&:asci_name)

    raise ActiveRecord::RecordInvalid.new(self) if names.include?(asci_name)
  end

  def asci_name
    ActiveSupport::Inflector.transliterate(name)
  end
end

Obviously, this is super inefficient to query whole table on each validation, but this is just to point you into one of the possible directions.

Another option would be going for a callback. Transliterating the name upon creation:

before_validation: :transliterate_name

def transliterate_name
  self.name = ActiveSupport::Inflector.transliterate(name)
end

It will first transliterate the name, then validate uniqueness of already transliterated name with the validation you have. Looks like a solution, definitely not as heavy as initial one.

Upvotes: 0

Related Questions