Rails: Special Use Cases Of MD5

Ganesh Sagare
3 min readJun 23, 2020

--

What is MD5?

The MD5 is hashing algorithm. It is a one-way cryptographic function. It accepts a message of any length as input and returns the fixed-length digest value.

There are various use-cases of md5. I have listed few of them below.

Use-case 1: Single Uniqueness Validation For Multiple Attributes.

Have you ever stuck in a situation, where you need to execute multiple uniqueness validations to insert single record in database?

These validations could be present in same model or different models. In that scenario adding uniqueness validation on each attribute tends to performance degradation. you’ll face this performance issue more often, if you have multiple records in database.

Lets consider a scenario:

2 Models: Product and Size.

Association between models: Product has many Sizes.

Uniqueness Validations We Need:

1. For product, sku and colour_code combination should be unique.

2. For size, product.sku, product.colour_code, size, attribute_size and source combination should be unique.

Standard approach could be as following:

app/models/product.rb

class Product < ApplicationRecord
# field :sku
# field :colour_code
# field :category
# field :name
# field :gender
# field :price
has_many :sizes

validates :sku, uniqueness: {scope: [:colour_code]}
end

app/models/size.rb

class Size < ApplicationRecord
# field :size
# field :attr_size
# field :source
belongs_to :product validates :size, :attribute_size, :source,
uniqueness: {scope: [:product_id]}
end

Now when inserting/updating size record, database validates all attributes and eventually it will impact on performance.

Now, we need a solution!

We can use only one md5 attribute for uniqueness validation.

So lets add one new attribute on size modal:

class AddMd5ToSizes < ActiveRecord::Migration[5.2]
def change
add_column :sizes, :md5, :string
end
end

And next step is to add logic for md5 attribute

class Size < ApplicationRecord
...
...
before_save do |record|
record.set_md5
end

private
def set_md5
_md5 = Digest::MD5.new
_md5.update "#{product.sku}#{product.colour_code}#{size}"\
"#{attribute_size}#{source}".downcase
self.md5 = _md5.hexdigest
end
end

add_index :companies_releases, [:company_id, :release_id], unique: trueAt the end, we’ll just add only one validation.

class Size < ApplicationRecord
# field :size
# field :attr_size
# field :source
# field :md5
belongs_to :product validates :md5, uniqueness: true
end

Ta…da….! Its done

Lets have a look at another use case of md5.

Use-case 2: Indexing On Variable Length Attributes.

Lets consider one scenario. Suppose we want to store profile image url in user model. Now our attribute is profile_url.

class User< ApplicationRecord
# field :first_name
# field :last_name
# field :profile_url
...
end

Now, our case is, we want to add unique index on profile_url attribute. As we know URL can be of variable length and it can vary from say 10 characters to 1000 characters, or more.

Any index on attribute with variable length, is very heavy operation, in terms of performance.

As a solution to such cases, we can take help of MD5, to add index.

Same as use-case 1, add new attribute to the model, to store md5 hash of URL. It is of fixed size, unique and gives better performance for index heavy operations.

# db/migrate/20200131101209_add_md5_users.rb
class AddMd5ToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :md5, :string
add_index :users, :md5, unique: true
end
end

# app/models/user.rb
class User < ApplicationRecord
...
...
before_save do |record|
record.set_md5
end
private def set_md5
_md5 = Digest::MD5.new
_md5.update "#{profile_url}"
self.md5 = _md5.hexdigest
end
end

In this way, with the help of md5, we can easily add uniqueness validation on such multiple and nested attributes. Also we saw, how to add index of variable sized attributes.

--

--

Ganesh Sagare
Ganesh Sagare

Written by Ganesh Sagare

Full Stack Developer At Josh Software

No responses yet