I'm working through the Railscast on implementing Devise and OmniAuth (along with the Devise documentation) -- currently, I've got a site going where visitors can sign up using their facebook accounts or by filling out a form.
I'm running into trouble when users that sign up via OmniAuth try to edit their profiles, though. Devise looks for the user's current password when they submit changes to their profiles, but those that logged in with facebook don't know their passwords (they're set automatically in the user model):
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
user = User.create(first_name:auth.extra.raw_info.first_name,
last_name:auth.extra.raw_info.last_name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20]
)
end
user
end
When a user edits his information, the app should not require password confirmation if he set up his account through OmniAuth. The tutorial suggests that the handy password_required? method will help me achieve this outcome. Specifically, adding this method to the user model means that it should only return true if the user didn't sign up through OmniAuth (the provider attribute would be nil in that case):
def password_required?
super && provider.blank?
end
Thus, a piece of code like:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put }) do |f| %>
<%= devise_error_messages! %>
<%= render :partial => "essential_user_info_inputs", :locals => { :f => f } %>
<%= render :partial => "inessential_user_info_inputs", :locals => { :f => f } %>
<% if f.object.password_required? %>
<%= render :partial => "password_inputs", :locals => { :f => f } %>
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %>
<% end %>
<%= f.submit "Update" %>
<% end %>
would theoretically only display password inputs when needed. It also suggests that Devise has built in logic saying that OmniAuth users don't need to use passwords to edit their accounts. I have no idea if this is true, but the tutorial kind of makes it look like that. But when an OmniAuth user tries to edit his account, I get "Current password can't be blank." Same thing with non-OmniAuth users (this makes sense, since the password fields don't show up on those users' edit pages either).
Some poking around confirms that the password_required? method is returning false, both when the user signed up through OmniAuth and through the site's regular user signup. Even when I change it to simply run the superclass method, it returns false.
Any ideas of what's going on with the password_required method? I can't find anything about it anywhere, but I feel like that's what's tripping things up right now.
Update:
This is now working, but not using the method outlined in the Railscast, which relies on requires_password? method, a topic that I still know nothing about. Instead, I implemented the solution outlined here, as suggested here. So I am now only requiring passwords to update non-OmniAuth accounts with the code:
class Users::RegistrationsController < Devise::RegistrationsController
def update
@user = User.find(current_user.id)
email_changed = @user.email != params[:user][:email]
is_facebook_account = !@user.provider.blank?
successfully_updated = if !is_facebook_account
@user.update_with_password(params[:user])
else
@user.update_without_password(params[:user])
end
if successfully_updated
# Sign in the user bypassing validation in case his password changed
sign_in @user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
end