Simple Short URLs

Creating short URLs
I want to share with you an idea, or how to reinvent the wheel, if you need a short URL, but can’t use side solutions, such as goo.gl, and have a short domain. You can make a URL shorter on your own. First, we need to create a model with a destination path, parameter fields, and an appropriate controller. After that, we can route.
get '/:id' => 'short_url#show'
Then, we can make a redirect to a required path with saved parameters. If you need to create a very short URL for a tweet, for example, a digital :id
can eat too many symbols in the result URL. To make it shorter, we can convert an :id
number to a string (what, actually, URL shorters do). I have resolved this issue with the help of the Base64 standart. In our case, it’s just an array with characters and their IDs (codes). To convert an :id
number to a short string, first, we convert it into a URL with Base64. This is the example of the ShortUrl
model.
class ShortUrl < ActiveRecord::Base
SYMBOLS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
DEFAULT_URL = ["http://", APP_CONFIG['host'], (APP_CONFIG['port'].present? ? ":#{APP_CONFIG['port']}" : '')].join
serialize :params
def self.find_by_code string
find decode(string)
end
def self.generate path, params
short_url_record = create do |t|
t.path = path
t.params = params
t.save
end
if short_url_record.id
[DEFAULT_URL, '/', encode(short_url_record.id)].join
else
nil
end
end
def full_path
[DEFAULT_URL, path].join
end
private
def self.encode number
base = SYMBOLS.length
res = []
begin
code = number % base
number /= base
res << SYMBOLS[code]
end until number == 0
res << 's'
res.reverse.join
end
def self.decode string
begin
string = string.match(/\A[s](.{1,5})\z/)[1]
i = string.length - 1
res = 0
string.each_char do |c|
res += (SYMBOLS.index(c) * (SYMBOLS.length ** i))
i -= 1
end
res
rescue
nil
end
end
end
If you want to leave both route variants (a digital ID and a string ID), you can put a prefix before an encoded string (in this case, it’s the s
character) and use regular expression constraints in the route.
get '/:id' => 'short_url#show', constraints: { id: /[s].{1,5}/ }
The number of characters is limited to five, because you can encode a really big number (1073741823) with five characters that can never be used. These are some examples of encoding.
pry(main)> ShortUrl.encode 12345
=> "sDA5"
pry(main)> ShortUrl.encode 1000000
=> "sD0JA"
pry(main)> ShortUrl.encode 1056698302
=> "s-----"
pry(main)> ShortUrl.encode 1827200481836
=> "altoros"
Then, you should decode.
pry(main)> ShortUrl.decode "sFFFFF"
=> 85217605
So, you can generate short URLs.
ShortUrl.generate(edit_user_path(@screener), reply_to: reply_to)
The result should look like this.
=> "http://ru.by/sKa"
Further reading
- Some Tricks on How to Optimize an Auto-Complete Combobox Using ZK and Java
- Two Powerful Iterator Methods
About the author
Nikolai Sharangovich is an experienced Ruby on Rails developer with a deep understanding of the object-oriented design and modern software principles. He likes to collaborate with product people to achieve a maximum impact. Find him on GitHub.