1

In my User model i have the following method :

def confirmation_token
    self.confirmation = loop do
        random_token = SecureRandom.urlsafe_base64(16, false)
        break random_token unless User.exists?(confirmation: random_token)
    end
end

this method will just create a random token to confirm user's email...

as you can see it loop while User.exists?(confirmation: random_token), which means it verify if there is no similar token already in user table.

my question is : if i have for example a lot of rows in "user table", i need to add index in this (confirmation) column for more performance ?

note (this method is executed just once per user ... the first time when user is sign up)

medBouzid
  • 7,484
  • 10
  • 56
  • 86

2 Answers2

1

Yes. If you're doing many searches on any particular column (in this case confirmation), you should index that column.

Tyler
  • 11,272
  • 9
  • 65
  • 105
  • i need to create a confirmation token when user sign up, if you validate uniqueness as you do here... you can see that you need a method to create a token first!! so : create token before validation first then validate column and finally call after_validation = 3 steps rather than one ... not convenient !!! – medBouzid Oct 09 '13 at 00:14
  • Gotcha -- I'll remove that bit. My answer should still be what you need though: add an index. – Tyler Oct 09 '13 at 00:55
0

If You are just searching by that value, then short answer was given to You.

Though there are some things to consider. First of all You probably would want that index to be unique, this will improve the performance quite a lot as table grows.

add_index :users, :confirmation_token, unique: true

Also You probably want a unique value instead of just random value. Though it's unlikely that it would generate a duplicate, it's still random, not unique value. One of the options would be generating and SHA using Digest class from some user column that You know is unique for this table, like this:

Digest::SHA1.hexdigest(user.email)

UPD: Asker is concerned about cases if someone would know that he uses email as a key and would use it to generate token.

This usually is solved by appending some unique key to the email before encrypting. You can generate such key with secure random and store it inside environment variable. In your .bashrc/.profile/.bash_profile or any other You use, do this:

export EMAIL_TOKEN_SECRET="M9SyIuuOPhakX0b6gjvcRnsRHY="

Then do like this:

Digest::SHA1.hexdigest("#{user.email}-#{ENV['EMAIL_TOKEN_SECRET'}")
Edgars Jekabsons
  • 2,833
  • 15
  • 20
  • i use the token for email confirmation, so it become a problem of security if i fix it with SHA1 on the user's email, imagine that someone discover that i use SHA1 in the email address, he can enter an aleatory email then use SHA1 to get the link for activate this email even if this email doesn't exist... – medBouzid Oct 09 '13 at 21:22
  • hi @EdgarsJekabsons the problem still even in your update answer, if you do SHA1 in your secret token you get this : "b1dd3c7e24f7509d28ce865843eec5231b88cb23" --> this encrypted value will still the same for all users : {encrypted-value-for-user-email}-b1dd3c7e24f7509d28ce865843eec5231b88cb23, so it's easy to do SHA1 in user email then add the value above to it :) i think my method still the best way to generate such token – medBouzid Oct 12 '13 at 14:01
  • Well, I don't know if a lot of seasoned developers would agree to rely on random values to generate unique tokens, but choice is yours. – Edgars Jekabsons Oct 12 '13 at 16:31
  • it's not question of choice if there is a secure alternative i will be thankful :) – medBouzid Oct 12 '13 at 17:25
  • Having a keys/passwords/access tokens defined in You environment on the host machine is considered a fine approach. For instance Heroku and all Heroku add-ons provide credentials in this fashion. If someone is able to get as far as seeing those values, You are compromised/screwed anyway. – Edgars Jekabsons Oct 12 '13 at 17:33
  • do you understand my original question? i want a confirmation link for example i send an email to user to tell him : please to use the site please click the link : http://www.domaine.com/token-confirmation-here, if we follow your logic the link will be http://www.domaine.com/encrypted_user_email-secret-hash, the secret hash here will be visible in the barre address so he still the same for each user, and you can just use SHA1 in user email to guess the link... hope this clarify to you what i means – medBouzid Oct 12 '13 at 18:00
  • I understand what You want, what I don't understand the issue with proposed solution SHA/MD5 are checksums, not a an encryption methods. They are designed not to be reversible. Maybe You don't understand what I am proposing, check this pastie for better understanding: http://pastie.org/8397519 – Edgars Jekabsons Oct 12 '13 at 18:09
  • ah ok you means apply SHA1 to email+secret-hash at the same time, here it's ok ;) – medBouzid Oct 12 '13 at 18:13
  • but i don't know why a random token is not the best in your opinion – medBouzid Oct 12 '13 at 18:14
  • I already explained that - it's random, but not unique. In my opinion it's not safe to apply unique constraint on such column when creating index (and searching by unique index is much faster). Using proposed method, I can be sure that it will always generate unique value as long as email is unique. – Edgars Jekabsons Oct 12 '13 at 18:47
  • can you see this please (note 80 votes for the answer in the link) : http://stackoverflow.com/questions/6021372/best-way-to-create-unique-token-in-rails – medBouzid Oct 12 '13 at 19:12