0
votes

I have a devise model called user. When a user signs up, they will be directed to fill out form called "userinfo". I have a model called userinfo. As soon as a new userinfo is created, I give each userinfo a unique token. I permit "token" in my userinfo controller. It works, but everytime I edit the form and update, the unique token changes too. I was thinking I should only show the first created token on the userinfo#show page. But if a user updates their userinfo form 5 times, 5 tokens will be created and 4 will be wasted.

So actual problem: Create unique token when userinfo#new happens and show it on the userinfo#show page. Unique token should not be updated when userinfo#edit and userinfo#update happens.

My userinfo model:

class Userinfo < ActiveRecord::Base
    belongs_to :user

      before_save :set_token

      def set_token
        self.token = rand(100000..999999)
      end
end

Userinfo controller:

class UserinfosController < ApplicationController
    before_action :find_userinfo, only: [:show, :edit, :update, :destroy, :log_impression]
    before_action :authenticate_user!

    def index
      @userinfors = Userinfo.search(params[:search])
    end

    def show
    end

    def new
        @userinformation = current_user.build_userinfo
    end

    def create
        @userinformation = current_user.build_userinfo(userinfo_params)
        if @userinformation.save
          redirect_to userinfo_path(@userinformation)
        else
          render 'new'
        end
    end

    def edit
    end

    def update
        if @userinformation.update(userinfo_params)
            redirect_to userinfo_path(@userinformation)
        else
            render 'edit'
        end
    end

    def destroy
        @userinformation.destroy
        redirect_to root_path
    end

    private
        def userinfo_params
            params.require(:userinfo).permit(:name, :email, :college, :gpa, :major, :token, :skills, :user_img)
        end

        def find_userinfo
            @userinformation = Userinfo.friendly.find(params[:id])
        end
end

View:

<%= @userinformation.token %>
1
Your "unique" token is only probably unique, by the way.Eric Duminil
I know, how can I make it unique?LizzyTheLearner
You use, SecureRandom.uuid if you don't mind the token to be string.ucpuzz
or SecureRandom.random_number*10000000000000000 :)whodini9

1 Answers

3
votes

Try something like this:

def set_token
  self.token ||= rand(100000..999999)
end

The ||= says, "set token to a random number unless token already has a value" (roughly).

BTW, in response to the comments below and on your original question, it is true that using:

rand(100000..999999)

is not such a good idea. Two problems were identified:

  1. There is a chance that the generated number will not be unique, and
  2. The probability that you attempt to assign non-unique numbers increases with the number of users and goes to 100% once you have 999,999 users.

As mentioned in the comments, using SecureRandom.uuid is a good thing if you don't mind the format of the UUID which is something like this:

ad9ed387-ec8e-4091-84b1-fe2ce2bbfcd4

In which case you would do something like:

def set_token
  self.token ||= SecureRandom.uuid
end

This is, by the way, what I do in my code.

With SecureRandom.uuid, the probability that you will generate duplicate tokens is vanishingly small. However, if you are worried about that very small chance, you could also enforce uniqueness at the DB level and in your model. Those are separate questions that you may want to post if you are interested in the answers.