Changnam Hong
Changnam Hong

Reputation: 1679

Devise error, SQLite3::ConstraintException: UNIQUE constraint failed: users.email

I was following this wiki to make user to login with their email OR username. But I got error like this. enter image description here

How can I fix it? My application controller is

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  skip_before_filter :verify_authenticity_token

  after_filter :store_location

  before_action :configure_permitted_parameters, if: :devise_controller?

  def store_location
    # store last url - this is needed for post-login redirect to whatever the user last visited.
    return unless request.get? 
    if (request.path != "/users/sign_in" &&
        request.path != "/users/sign_up" &&
        request.path != "/users/password/new" &&
        request.path != "/users/password/edit" &&
        request.path != "/users/confirmation" &&
        request.path != "/users/sign_out" &&
        !request.xhr?) # don't store ajax calls
      session[:previous_url] = request.fullpath 
    end
  end

  def after_sign_in_path_for(resource)
    session[:previous_url] || root_path
  end

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:username, :email, :password, :password_confirmation, :remember_me) }
    devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:login, :username, :email, :password, :remember_me) }
    devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:username, :email, :password, :password_confirmation, :current_password) }
  end

end

My models/user.rb looks like

class User < ActiveRecord::Base
  has_many :hasuk_houses, dependent: :destroy
  has_many :favorite_hasuk_houses
  has_many :favorites, through: :favorite_hasuk_houses, source: :hasuk_house


  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable,
         :omniauthable, :omniauth_providers => [:facebook]
  devise :validatable, :authentication_keys => [:login]

  attr_accessor :login

  validate :validate_username

  def validate_username
    if User.where(email: username).exists?
      errors.add(:username, :invalid)
    end
  end

  def email_required?
    false
  end

  def login=(login)
    @login = login
  end

  def login
    @login || self.username || self.email
  end


  def self.find_for_database_authentication(warden_conditions)
    conditions = warden_conditions.dup
    if login = conditions.delete(:login)
      where(conditions.to_hash).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
    else
      where(conditions.to_hash).first
    end
  end


  #facebook login
  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.email = auth.info.email
      user.password = Devise.friendly_token[0,20]
      user.name = auth.info.name   # assuming the user model has a name
    end
  end

  def self.new_with_session(params, session)
    super.tap do |user|
      if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"]
        user.email = data["email"] if user.email.blank?
      end
    end
  end

end

Upvotes: 0

Views: 1433

Answers (1)

x6iae
x6iae

Reputation: 4164

What you have up there is an error generated because the email you entered as already been used for another user in your database.

Now, this is a uniqueness validation error, which gets trigered when there is an attempt at duplicating a column with the uniqueness validation set.

There are different level of validations, there is the model validation, which you can set in your Model, and managed by Rails, and there is the database level validation.

The above is an example of a database level validation.

What you can do in this case is to set a corresponding Model level validation in your User Model:

#user.rb:
class User < ActiveRecord::Base
  ...
  validates :email, uniqueness: true
  ...
end

This will provide another level of validation, which will be triggered by the app, and handled by the app, before giving control to the database.

You can now handle this validation anyhow you want.

Upvotes: 2

Related Questions