References:
Rails 5.0.1
omniauth 1.8.1
omniauth-facebook 5.0.0
I have users logged in with email + password and others with facebook account.
The main issue is to make possible to facebook's users edit their own account without needing to use the password, because they just don't have. The solution in this post so I can add this class:
def update
if current_user.provider == "facebook"
params.delete("current_password")
resource.update_without_password(user_params)
else
resource.update_with_password(user_params)
end
redirect_to root_path
end
So I have this:
routes.br
devise_for :users, controllers: { omniauth_callbacks: "omniauth_callbacks" }
and inside the omniauth_callbacks_controller.rb I add this update
function:
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def update
if current_user.provider == "facebook"
params.delete("current_password")
resource.update_without_password(user_params)
else
resource.update_with_password(user_params)
end
redirect_to root_path
end
def facebook
user = User.find_for_facebook_oauth(request.env['omniauth.auth'])
if user.persisted?
sign_in user
redirect_to root_path
set_flash_message(:notice, :success, kind: 'Facebook') if is_navigational_format?
else
session['devise.facebook_data'] = request.env['omniauth.auth']
redirect_to new_user_registration_url
end
end
def user_params
params.require(:user).permit(:first_name, :last_name, :phone, :picture, :facebook_picture_url)
end
end
The problem is that the devise doesn't read this function. So if we add a byebug inside it will not stop there.
The only way to override this update function is to add this configurations below.
routes.br
devise_for :users, controllers: { registrations: 'registrations' }
registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def update
if current_user.provider == "facebook"
params.delete("current_password")
resource.update_without_password(user_params)
else
resource.update_with_password(user_params)
end
redirect_to root_path
end
def facebook
user = User.find_for_facebook_oauth(request.env['omniauth.auth'])
if user.persisted?
sign_in user
redirect_to root_path
set_flash_message(:notice, :success, kind: 'Facebook') if is_navigational_format?
else
session['devise.facebook_data'] = request.env['omniauth.auth']
redirect_to new_user_registration_url
end
end
def user_params
params.require(:user).permit(:first_name, :last_name, :phone, :picture, :facebook_picture_url)
end
end
The only problem with this second approach is that if I try to login with facebook I receive this error message:
The action 'facebook' could not be found for Devise::OmniauthCallbacksController
My devise configuration:
devise.rb
Devise.setup do |config|
config.omniauth :facebook, ENV["FB_ID"], ENV["FB_SECRET"],
scope: 'email',
info_fields: 'email, first_name, last_name',
image_size: 'large', # 50x50, guaranteed ratio
secure_image_url: true
...
end
Just in case somebody else has a similar problem. The thing was that the routes.rb
needed to specify both of the controllers being overwritten, like:
devise_for :users, controllers: { registrations: 'registrations' , omniauth_callbacks: 'omniauth_callbacks' }