简体   繁体   中英

Devise - Omniauth – Hiding password fields if the user is signed in through Facebook

Using Devise with Omniauth I was successfully able to allow users to login with their Facebook accounts. With the help of the Omniauth wiki I was also able to disable having to put in a password when editing their account.

The current problem I'm faced with is hiding the password fields in my registrations#edit view if they signed up via Facebook. As a newcomer to both gems I'm still trying to adjust. So when it comes to setting up the necessary helper method(s) I'm sort've at a loss.

As instructed by the wiki here's what my Registrations controller looks like:

class RegistrationsController < Devise::RegistrationsController
  before_filter :configure_permitted_parameters, if: :devise_controller?

  def update
    @user = User.find(current_user.id)

    successfully_updated = if needs_password?(@user, params)
      @user.update_with_password(devise_parameter_sanitizer.sanitize(:account_update))
    else
      # remove the virtual current_password attribute
      # update_without_password doesn't know how to ignore it
      params[:user].delete(:current_password)
      @user.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
    end

    if successfully_updated
      set_flash_message :notice, :updated
      # Sign in the user bypassing validation in case their password changed
      sign_in @user, :bypass => true
      redirect_to after_update_path_for(@user)
    else
      render "edit"
    end
  end

  private

  # check if we need password to update user data
  # ie if password or email was changed
  # extend this as needed
  def needs_password?(user, params)
    user.email != params[:user][:email] ||
      params[:user][:password].present? ||
      params[:user][:password_confirmation].present?
  end

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) do |u|
      u.permit(:first_name, :last_name, :email, :password, :password_confirmation)
    end
    devise_parameter_sanitizer.for(:account_update) do |u|
      u.permit(:first_name, :last_name, :email, :password, :password_confirmation)
    end
  end
end

And here is my registrations#edit view:

<% provide :title, 'Edit Profile' %>

<h2>Edit <%= resource_name.to_s.humanize %></h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
  <%= devise_error_messages! %>

  <div><%= f.label :first_name %><br />
  <%= f.text_field :first_name %></div>

  <div><%= f.label :last_name %><br />
  <%= f.text_field :last_name %></div>

  <div><%= f.label :email %><br />
  <%= f.email_field :email %></div>

  <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
    <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
  <% end %>

  <div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
    <%= f.password_field :password, autocomplete: "off" %></div>

  <div><%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "off" %></div>

  <div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
    <%= f.password_field :current_password, autocomplete: "off" %></div>

  <div><%= f.submit "Update" %></div>
<% end %>

UPDATE

After some extensive research I was able to find a question that inderictly answered what I was looking for in terms of hiding the input fields (second to last comment in the question). The only problem is that for some reason it triggers a password validation error despite it not being there...

   <div>
    <%= f.label :first_name %><br />
    <%= f.text_field :first_name %>
  </div>

  <div>
    <%= f.label :last_name %><br />
    <%= f.text_field :last_name %>
  </div>

  <% if user_signed_in? && !current_user.provider == 'facebook' %>
    <div>
      <%= f.label :email %><br />
      <%= f.email_field :email %>
    </div>

    <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
      <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
    <% end %>

    <div>
      <%= f.label :password %><br />
      <%= f.password_field :password %>
    </div>

    <div>
      <%= f.label :password_confirmation %><br />
      <%= f.password_field :password_confirmation %>
    </div>

    <div>
      <%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
      <%= f.password_field :current_password %>
    </div>

After searching through the site I have FINALLY found out how to get this to work.

My first order of business was to to use the first code example for the registrations controller from this devise wiki

  def update
    # For Rails 4
    account_update_params = devise_parameter_sanitizer.sanitize(:account_update)
    # For Rails 3
    # account_update_params = params[:user]

    # required for settings form to submit when password is left blank
    if account_update_params[:password].blank?
      account_update_params.delete("password")
      account_update_params.delete("password_confirmation")
    end

    @user = User.find(current_user.id)
    if @user.update_attributes(account_update_params)
      set_flash_message :notice, :updated
      # Sign in the user bypassing validation in case their password changed
      sign_in @user, :bypass => true
      redirect_to after_update_path_for(@user)
    else
      render "edit"
    end
  end

Next was adding a method to override the validation for the user's current password just above the code above. Special thanks to Lauri Laine for her answer in this post: Editing Users With Devise and Omniauth

  # Overwrite update_resource to let users to update their user without giving their password
  def update_resource(resource, params)
    if current_user.provider == "facebook"
      params.delete("current_password")
      resource.update_without_password(params)
    else
      resource.update_with_password(params)
    end
  end

Lastly I had to add :current_password as a virtual attribute to my user model and everything worked!

attr_accessor :current_password

Hopefully this helps anyone who has/will encounter this problem. I know it had me stumped for a minute but glad I was able to figure it all out. Will be testing this soon in conjunction with omniauth's twitter gem.

THe is a different approach possible.

From this page: https://github.com/plataformatec/devise/tree/master/app/views/devise I have copied shared and session folders to

app/views/devise/

After that, I was able to edit the views and hide whatever I wanted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM