SecretId
SecretId is a flexible solution for masking the identifiers of ActiveRecord. Using the Hashids.rb gem we encode the value of your defined primary key to hide the real value to the user.
This gem does not guarantee the security of masked ids, since Hashids it is reversible.
SecretId has been Deprecated
This repository has been deprecated and will no longer be maintained.
If your looking for a real solution i strongly recommend friendly_id.
Getting started
You can add it to your Gemfile
:
gem 'secret_id'
Run the bundle command to install it.
Configuring models
After that, extend the model to SecretId
and add secret_id
to this, like below.
class Post < ActiveRecord::Base
extend SecretId
secret_id
end
Now you can try it in your rails console
.
> post = Post.create
=> #<Post id: 1, ...>
> post.id
=> 1
> post.secret_id
=> "v40"
> Post.find("v40")
=> #<Post id: 1, ...>
> Post.find(1, secret_id: false)
=> #<Post id: 1, ...>
> Post.decode_id("v40")
=> 1
> Post.encode_id(1234567890)
=> "xrjlkB1"
Options
- salt: If you want your identifiers to be different than some other website that are using the same gem, you can use a random string. By default is the name of the model. Note that this change means that all encoded values will change, therefore any stored url will be invalid.
- min_length: The smallest possible length of encoded value, by default is set to 3.
- alphabet: Possible characters in what will consist the encoded value, default is a alphanumeric case sensitive string.
class Post < ActiveRecord::Base
extend SecretId
secret_id salt: 'bring_your_own_salt', min_length: 5,
alphabet: 'define_your_own_alphabet'
end
Configuring views
In your views, use @post
or @post.secret_id
instead of @post.id
for create links, like any of below.
<%= link_to "Post", @post %>
<%= link_to "Post", post_path(@post) %>
<%= link_to "Post", post_path(@post.secret_id) %>
And if you want to show the id remember use secret_id
method.
Configuring controllers
For controllers, you only can find the resource with the method find
(At least for now). For example, suppose you have a before_action
for action show
to find_post
method, like below.
def find_post
@post = Post.find(params[:id])
end
Another good news is that this runs smoothly over associations.
def find_user_post
current_user.posts.find(params[:id])
end
The above works without problem (even if instead of params[:id]
, it were a set of ids). But the next example it will not work.
def find_post
@post = Post.find_by!(id: params[:id])
end
This method, as find_by
, where
, and everything like that, its not working for now. But not all is lost. If you want scope your result you can do something like this.
def find_post
@post = Post.where(visible: true).find(params[:id])
end
But if you are stubborn you can always use the wildcard for decode id manually.
def find_post
@post = Post.find_by!(id: Post.decode_id(params[:id]))
end
I personally do not recommend this, because if the parameter is not a valid encoded id, it will look for the id nil
.
Contributing
Any contribution is welcome.
Reporting issues
Please try to answer the following questions in your bug report:
- What did you do?
- What did you expect to happen?
- What happened instead?
Make sure to include as much relevant information as possible. Ruby version, SecretId version, OS version and any stack traces you have are very valuable.
Pull Requests
-
Add tests! Your patch won't be accepted if it doesn't have tests.
-
Document any change in behaviour. Make sure the README and any relevant documentation are kept up-to-date.
-
Create topic branches. Please don't ask us to pull from your master branch.
-
One pull request per feature. If you want to do more than one thing, send multiple pull requests.
-
Send coherent history. Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before sending them to us.