0

I'm currently developing a sign-up form for a project. When a user clicks the submit button, the controller checks if any of the fields are empty, then checks if one of the fields (cedula) is an integer, finally, it checks if the entered cedula is already in the database. If it's not, then the it proceeds to create the new record and store it in the database, as you can see below:

app.rb

post '/signup' do
if params[:nombre].blank? || params[:cedula].blank? || params[:password].blank?
    redirect './signup', :error => "Por favor, complete todos los campos."
elsif params[:cedula].is_a?(Integer)
    redirect './signup', :error => "Cédula inválida, intente nuevamente."
elsif User.select(:cedula).exists?
    redirect './signup', :error => "La cédula #{params[:cedula]} ya se encuentra en uso. Intente nuevamente."
else
    password_salt = BCrypt::Engine.generate_salt
    password_hash = BCrypt::Engine.hash_secret(params[:password], password_salt)

    @usuarios = User.new(nombreUsuario: params[:nombre],
    cedulaUsuario: params[:cedula], passwordUsuario: password_hash,
    nivelAcceso: params[:rol])

    if @usuarios.save
        redirect './signup', :notice => "Usuario creado exitosamente."
    else
        redirect './signup', :error => "Ha ocurrido un error, intente nuevamente."
    end
end
end

If the cedula entered is already in the database, the page reloads and shows a flash message indicating the user that it's already in use. The issue with this is, no matter the value the user may input, the flash message indicating an unsuccessful register always shows up. I can only store one user into the database if the table is completely empty, otherwise, I'm unable to.

After the only successful insert, the query being sent to the database, according to the console, is the following:

Log

127.0.0.1 - - [01/Aug/2015:22:01:21 -0430] "GET /signup HTTP/1.1" 200 1294 0.0032
D, [2015-08-01T22:01:35.057431 #14779] DEBUG -- :   User Exists (0.3ms)  SELECT  1 AS one FROM `usuarios` LIMIT 1
127.0.0.1 - - [01/Aug/2015:22:01:35 -0430] "POST /signup HTTP/1.1" 303 - 0.0032
127.0.0.1 - - [01/Aug/2015:22:01:35 -0430] "GET /signup HTTP/1.1" 200 1329 0.0034

It's not clear for me why "SELECT 1 AS one FROM usuarios LIMIT 1" is being sent to the server. I've tried multiple queries according to QueryMethods and FinderMethods with no avail so far.

Any help would be greatly appreciated!

Thanks in advance.

1 Answers1

0

I think you're using the select method incorrectly at:

elsif User.select(:cedula).exists?
  redirect './signup', :error => "La cédula #{params[:cedula]} ya se encuentra en uso. Intente nuevamente."

According to the docs that returns a relation object, so if there are any users at all then #exists? will return true: http://apidock.com/rails/ActiveRecord/QueryMethods/select

If you want to check if that cedula already exists in the database, use something like:

elsif User.where(cedula: params[:cedula]).present?
  redirect './signup', :error => "La cédula #{params[:cedula]} ya se encuentra en uso. Intente nuevamente."

However, be aware that this will not protect your database in a race condition.

spejamchr
  • 178
  • 2
  • 8
  • This worked, thanks! But, I'm curious, how should look the code in order to protect the database in a race condition? Optimistic locking? – Angel Perez Aug 02 '15 at 06:25
  • The answer here encourages optimistic locking: http://stackoverflow.com/questions/3037029/how-do-i-avoid-a-race-condition-in-my-rails-app. And this blog suggests adding the validation right into the database: https://rietta.com/blog/2015/05/04/validates-uniqueness-race-condition-in-ruby-on-rails/ – spejamchr Aug 03 '15 at 16:21