I'm using Devise (form) and Omniauth Twitter. My sign up form fields are:
Both sign up works fine when there is no existing record with the same username. User can sign up either via Twitter or email form.
The problem is:
If user tries to sign up via form using an existing username, it doesnt allow. It is OKAY.
But when user tries to sign up via Twitter and if twitter nickname (username in my website) already exists, it doesnt block the sign up, it transfers the existing account to the new sign up Twitter, it updates existing user details with the ones from Twitter profile (API) . How can I stop it?
Thank you!
omniauth_callbacks_controller.rb
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def all
designer = Designer.from_omniauth(request.env['omniauth.auth'])
if designer.persisted?
sign_in_and_redirect designer, notice: "Signed in!"
else
session["devise.designer_attributes"] = designer.attributes
redirect_to new_designer_registration_url
end
end
alias_method :twitter, :all
end
designer.rb
class Designer < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, omniauth_providers: [:twitter]
validates_presence_of :email
validates_uniqueness_of :email
validates_presence_of :username
validates_uniqueness_of :username
validates_presence_of :password, if: :password_required? # recommended
validates_confirmation_of :password, if: :password_required? # recommended
validates_length_of :password, within: password_length, allow_blank: true # recommended
extend FriendlyId
friendly_id :username, use: [:slugged, :history]
has_many :posts
mount_uploader :avatar, AvatarUploader
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |designer|
designer.provider = auth.provider
designer.uid = auth.uid
designer.slug = auth.info.nickname
designer.username = auth.info.nickname
designer.twitter_username = auth.info.nickname
designer.email = auth.info.email
designer.password = Devise.friendly_token[0, 20]
designer.fullname = auth.info.name
end
end
def self.new_with_session(params, session)
if session["devise.designer_attributes"]
new(session["devise.designer_attributes"]) do |designer|
designer.attributes = params
designer.valid?
end
else
super
end
end
def password_required?
super && provider.blank?
end
def update_with_password(params, *options)
if encrypted_password.blank?
update_attributes(params, *options)
else
super
end
end
end
controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:designer).permit(:username, :fullname, :email, :password, :password_confirmation)
end
def account_update_params
params.require(:designer).permit(:username, :fullname, :email, :location, :website, :twitter, :bio, :password, :password_confirmation, :current_password)
end
protected
def after_sign_up_path_for(resource)
edit_designer_path(current_designer) if current_designer
end
end
devise/registration/new.html.erb
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :fullname, required: true, placeholder: "Fullname", label: false, input_html: { maxlength: 120 } %>
<%= f.input :username, unique: true, required: true, placeholder: "Username", label: false, input_html: { maxlength: 120 } %>
<%= f.input :email, required: true, placeholder: "Email", label: false, input_html: { maxlength: 120 } %>
<% if f.object.password_required? %>
<%= f.input :password, required: true, placeholder: "Password (minimum 6 chars)", label: false, input_html: { maxlength: 120 } %>
<% end %>
</div>
<div class="form-actions tl pl1">
<%= f.button :submit, "Sign up" %>
</div>
<% end %>
From this I redirect to profile editing for additional profile information which is designer/edit.html.erb
I fixed it with adding the codes below to designer.rb 🤦♂️
def should_generate_new_friendly_id?
slug.blank? || username_changed?
end