Sometimes you don’t want to reveal the real id of the object in the system to the user for some reason. For example, you don’t want to reveal the number of items in the system, or let the user view all of them by simply changing the id in the address.
The most obvious and easy way to do it is to generate a fake id for the object and use it instead.
Lets say we have a model named Foo and you want it to have a fake id. Here’s the code for it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class Foo < ActiveRecord::Base
before_validation_on_create :generate_fake_id
def to_param
fake_id
end
protected
def generate_fake_id
string = random_string
while Foo.find_by_fake_id(string)
string = random_string
end
self.fake_id = string
end
def random_string(size = 8)
chars = (('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a)
(1..size).collect{|a| chars[rand(chars.size)] }.join
end
end |
Now, when you create a Foo with for example “Foo.create(:name => ‘first foo’)”, the model generates a random string of 8 characters and stores it in
fake_id. The fake id is only generated once, on creation, so it’s not changed later on.
Now, for the helpers. Suppose you have
map.resources :foos in your routes.rb. The helper you user before,
foo_path(@foo) now generates a url with the fake id (foos/Hd45jdg3), because of the
to_param method. All you have to do, is to change your foos_controller this way:
1
2
3
4
5
|
class FoosController < ApplicationController
def show
@foo = Foo.find_by_fake_id(params[:id])
end
end |
The uniqueness of the
fake_id is guarantied by the Foo.find_by_fake_id call in the
generate_fake_id method. Yes, it does add an extra query to the database, but it’s not really impaction performance much unless you are generating a lot of objects all of the time.
You can change the way the fake id looks like by modifying the array used in
random_string. For example if you want to eliminate symbols that look much alike you can have it this way:
1
2
3
4
|
def random_string(size = 8)
chars = (('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a) - %w(i o 0 1 l O)
(1..size).collect{|a| chars[rand(chars.size)] }.join
end |
And also: don’t forget to add the
fake_id field to the table in the database.
Sorry, comments are closed for this article.