PhoenixDown
PhoenixDown

Reputation: 355

Do not save user when validation fails but redirect as if it passed

I'm new to both Ruby and ROR. I want to present users with validation errors (e.g. password missing, email missing) when they sign up. If they submit the desired input I create the user and redirect them to the login page If they provide an email address already in the db and a password that passes validation I don't want to save the user but I do want to redirect them to the login page. The idea being not to give away who is already a user by presenting them with a duplicate email error.

I've got the signup form working. I'm just stumped on how to go about also redirecting the user to the login page if they submit a duplicate email and a password that passes validation. Would I need to setup a custom validation for this?

As an example, assume I have [email protected] in my user table and a user signs up with the following:

Case 1:

email = [email protected]
password = null
result = user redirected to sign up page with error about password being blank

Case 2:

email = [email protected]
password = p@55w0rd
result = user redirected to login page with success message

Case 3:

email = [email protected]
password = p@55w0rd
result = user redirected to login page with success message

UsersController

class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user].permit(:email, :password))
    if @user.save
      redirect_to root_url, :notice => "signed up!"
    else
      render 'new'
    end
  end

end

User Model

class User < ActiveRecord::Base
  attr_accessor :password
  before_save :encrypt_password

  validates_confirmation_of :password
  validates_presence_of :password, :on => :create
  validates_presence_of :email

  def encrypt_password
    if password.present?
      self.password_salt = BCrypt::Engine.generate_salt
      self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
    end
  end

  def self.authenticate email, password
    user = find_by_email(email)
    if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
      return user
    end

    return nil
  end

  def exists?
    if find_by_email(email)
      return true
    end

    return false
  end

end

Upvotes: 1

Views: 1214

Answers (2)

Raj
Raj

Reputation: 22956

Modify the else path in your User Controller like this

else
      redirect_to login_path
end

If you are using devise and simple_form, all those (redirection, displaying error on invalid data) will handled automatically for you.

To add uniqueness constraint on email, do this in your model:

 validates :email, uniqueness: true

Upvotes: 1

Anonymous1235
Anonymous1235

Reputation: 21

You could specify the redirect in your UsersController:

class UsersController < ApplicationController
    def new
       @user = User.new
    end

    def create
       @user = User.new(params[:user].permit(:email, :password))
       if @user.save
          redirect_to root_url, :notice => "signed up!"
       else
          redirect_to login_url, :notice => "There was something wrong with your e-mail or password"
       end
    end
end

I really recommend using Devise - it will take care of these one-off cases for you: https://github.com/plataformatec/devise

If you want to be more hands-on with your authentication I would recommend the has_secure_password method: http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html has_secure_method takes care of salting your password and does validations as well.

Upvotes: 2

Related Questions