Spree Uname Login/Signup
Spree default provides login/signup with just email.
But now a days many E-Coms are taking a trend to introduce username or phone number as alternate login options.
This article is all about how to use alternate options (other than email) for login/signup in a Spree app. I am targeting username here but using other options will be much similar to that.
Start with adding DB migration to add uname
attribute to User
model.
$ rails g migration add_uname_to_spree_users
class AddUnameToSpreeUsers < ActiveRecord::Migration def up add_column :spree_users, :uname, :string add_index :spree_users, :uname Spree::User.where(uname: nil).each do |user| user.send(:set_uname) user.save! end end def down remove_index :spree_users, :uname remove_column :spree_users, :uname end end
In migration, you will notice a loop to set_uname
for existing users.
# In User model (user_decorator.rb) def set_uname if self.uname.blank? && self.email.present? # Fetch string prior to @ from emailID username = self.email.split(/@/)[0] # remove chars other than numbers and alphabets username = username.titleize.gsub(/[^a-zA-Z0-9]/, '') count = 0 # add counter with username if some other user already has it while Spree::User.find_by('lower(uname) = :value', value: username.downcase) username += (count += 1).to_s end self.uname = username end end
This set_uname
ensures username for each user to be extracted out from its email and only allowing alphabets and numbers to be a part of uname
. You can change logic here to suit your need.
If you want to auto assign username to user, you can
# In User model (user_decorator.rb) before_validation :set_uname, on: :create
We are set now to code/customise Spree login/signup process.
Signup
If you want user to set uname of their choice while signing up set
# In config/initializers/spree.rb Spree::PermittedAttributes.user_attributes.push(:uname)
Update signup form accordingly to have uname text field.
Login
Change login form email
text_field to login
text field,
# CHANGE <%= f.email_field :email %> # TO <%= f.text_field :login %>
Add login
authentication key to devise,
# In config/initializers/devise.rb Devise.setup do |config| config.authentication_keys = [ :login ] end
Change the way devise finds user,
# In User model (user_decorator.rb) def self.find_for_database_authentication(warden_conditions) conditions = warden_conditions.dup if login = conditions.delete(:login) where(conditions.to_hash).where('lower(uname) = :value OR lower(email) = :value', value: login.downcase).first else conditions[:email].downcase! if conditions[:email] where(conditions.to_hash).first end end
And you should be good to go.