Remove extra white spaces.all

Ever added the uniqueness validation to a model

class Person < ApplicationRecord
  validates :name, uniqueness: { case_sensitive: false }
end

but just adding the above alone will not prevent the duplicates

Soon you will start seeing duplicates and you’ll wonder how’s that happening. After spending some time (or hours) debugging you will notice that users are adding extra white spaces to bypass the uniqueness validation. Smart hn!!

Bagel & Cream Cheese
Bagel & Cream  Cheese
Bagel  & Cream Cheese

Means now you have to take care of extra white space, and in many models. Lets create a module to handle that.

module StripedColumns
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    StripedColumnsDefaultOptions = { squeeze: false }
    
    # add has_striped_columns as a class method
    def has_striped_columns(options = StripedColumnsDefaultOptions)
      options[:squeeze] = { string: true, text: true } if options[:squeeze] == true

      before_validation do
        self.class.columns.each do |column| 
          # only run for String or Text columns
          next unless column.type.in? %i(string text)
          # make sure value is not nil
          next unless value = self.send(column.name)
          # run :if condition passed as options
          next unless options[:if].to_proc.call(self) if options[:if]
          
          # check if value is a string
          if value.kind_of?(String)
            # remove white spaces around the text
            value = value.strip
            # grab the value after running the options
            value = apply_striped_columns_options(column, value, options)
            # assign the new value to the column
            self.send("#{column.name}=", value)
          end
        end
      end
    end
  end

private

  def apply_striped_columns_options(column, string, options)
    if squeeze_opts = options[:squeeze]
      if (squeeze_opts[:string] == true && column.type == :string) ||
        (squeeze_opts[:text] == true && column.type == :text)
        # remove extra white spaces between words
        string = string.squeeze(" ")
      end
    end
    string
  end
end

# add it to ActiveRecord::Base to make it available to all the models
ActiveRecord::Base.include(StripedColumns)

That little module will handle all the extra white space issues

class Person < ApplicationRecord
  # has_striped_columns                    # remove spaces around
  # has_striped_columns, if: :is_true?     # remove spaces around only if is true
  # has_striped_columns, squeeze: true     # remove spaces around + remove extra space between words
  # has_striped_columns, squeeze: :string  # remove spaces around + remove extra space between words for string column only
  # has_striped_columns, squeeze: :text    # remove spaces around + remove extra space between words for text column only

  validates :name, uniqueness: { case_sensitive: false }
end