0

I'm using Devise (form) and Omniauth Twitter. My sign up form fields are:

  • username (unique, required)
  • email (unique, required)
  • full name
  • password

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

Designer
  • 1,061
  • 1
  • 12
  • 26
  • What are the provider values when user created via regular form and the oauth? – Anton Jan 28 '18 at 07:57
  • @Anton hey mate, I just added additional codes for that. I hope thats what you wanted to see. :D – Designer Jan 28 '18 at 12:46
  • Hey! 1. Please post here the devise.rb initializer. 2. Please initiate another sign up call with taken username and post here the params that you pass the server and a server output. I can thinks of a way that devise "ignores" your username uniqueness but the part of fetching and updating existing record is very strange. You can see that the user is fetched or created by provider value and uid.. the username is not even there. – Anton Jan 29 '18 at 13:38
  • Ohh I think I see what's up here.. You probably created a user with a regular form and then appended to that record your twitter identity. – Anton Jan 29 '18 at 13:41
  • @anton hey mate, yeah that is the issue. Example: someone signs up via devise form with an username elonmusk, then someone else comes and signs up via Twitter with the username twitter.com/elonmusk. In this case, the second user takes over the first sign up, but instead it should block the second user's sign up and force to write a new unique username – Designer Jan 30 '18 at 10:47
  • Can it be about it using the Session[] that comes from Twitter over the form input I enter in username field? – Designer Jan 30 '18 at 17:42

1 Answers1

0

I fixed it with adding the codes below to designer.rb ‍♂️

  def should_generate_new_friendly_id?
    slug.blank? || username_changed?
  end
Designer
  • 1,061
  • 1
  • 12
  • 26