I tried asking this question - and didn't find any help.
http://stackoverflow.com/questions/33493369/rails-devise-omniauth-problems-with-setup
I gave up trying to solve the problem and made an entirely new app with nothing else in it so that I could try to reduce the scope for other errors interfering.
In my new app, I now get an error when I click on the new registration/new user link.
I have followed the rails casts tutorials (having tried about 20 others) to get this setup. 1.5 years in and I am still struggling.
The problem is with the way the strategies are defined in the controller. I have 4 strategies (twitter, Facebook, google and linkedin) and am I am currently getting a different error for each of them when I try clicking on the links to create a new registration with those accounts:
For Twitter: Unknown action The action 'twitter' could not be found for Users::AuthenticationsController
For Facebook:
Given URL is not permitted by the Application configuration: One or more of the given URLs is not permitted by the App's settings. It must match the Website URL or Canvas URL, or the domain must be a subdomain of one of the App's domains.
This error is because I can't figure out Facebook's documentation. It shows how to use js to login with Facebook where I am trying to use gems in Rails. I'm not worried about this error. I think it has something to do with my website not being defined as local host, although I can't find anywhere to but a callback url in Facebook's developer console. My question doesn't relate to this problem, I'll find help to sort this out another time.
For LinkedIn:
Safari can’t open the page “https://www.linkedin.com/uas/oauth2/authorization?client_id=LINKEDIN_DEV_ID&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fusers%2Fauth%2Flinkedin%2Fcallback&response_type=code&scope=r_basicprofile+r_emailaddress&state=3fef961c10410464cd5b0ca49b25112ce53fb65f1a3c794f”.
The error is: “cannot decode raw data” (NSURLErrorDomain:-1015) I have an oauth2 callback defined as:
http://localhost:3000/users/auth/linkedin/callback
I don't know what's broken here.
For Google:
translation missing: en.devise.authentications.user.failure
The new registrations view just refreshes when i click this link and an error message says the above. I don't know what's causing this error either.
Each of the errors is different.
I have a folder in my controllers folder called users. Inside that I have two controllers as follows:
Authentications controller:
class Users::AuthenticationsController < Devise::OmniauthCallbacksController
before_action :set_authentication, only: [:destroy]
def index
@authentications = current_user.authentications if current_user
end
def create
omniauth = request.env["omniauth.auth"]
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
sign_in_and_redirect_user(:user, authentication.user.profile)
elsif current_user
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
redirect_to user.profile_url
else
user = User.new
user.omniauth(omniauth)
if user.save!
sign_in_and_redirect_user(:user, user.profile)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_registration_url
end
end
end
def destroy
@authentication.destroy
respond_to do |format|
format.html { redirect_to root_path }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_authentication
@authentication = current_user.authentications.find(params[:id])
end
end
Registrations controller:
class Users::RegistrationsController < Devise::RegistrationsController
#before_filter :check_permissions , :only => [ :new, :create, :cancel ]
#skip_before_filter :require_no_authentication
# before_action :configure_permitted_parameters, if: :devise_controller?
def check_permissions
authorize! :create, resource
end
def index
if params[:approved] == "false"
@users = User.find_all_by_approved(false)
else
@users = User.all
end
end
def create
super
session[:omniauth] = nil unless @user.new_record?
end
# THIS IS A SUGGESTION FROM SITEPOINT TUTORIAL
# protected
# def configure_permitted_parameters
# devise_parameter_sanitizer.for(:sign_up) << [:first_name, :last_name]
# end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password )
end
def build_resource(*args)
super
if session[:omniauth]
@user.apply_omniauth(session[:omniauth])
@user.valid?
end
end
end
User.rb has
devise
:omniauthable, :omniauth_providers => [:facebook, :linkedin, :twitter, :google_oauth2 ]
has_many :authentications, :dependent => :delete_all
def apply_omniauth(omniauth)
self.email = auth['extra']['raw_info']['email']
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => auth['credentials']['token'])
end
def password_required?
(authentications.empty? || !password.blank?) && super
end
In my routes.rb I have:
devise_for :users,
:controllers => {
:registrations => "users/registrations",
:omniauth_callbacks => "users/authentications"
# :omniauth_callbacks => 'users/omniauth_callbacks',
}
get '/auth/:provider/callback' => 'users/authentications#create'
get '/sign_out', :to => 'users/authentications#destroy'
In my omniauth.rb I have:
require 'omniauth-facebook'
require 'omniauth-google-oauth2'
require 'omniauth-twitter'
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
end
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_KEY'],
:scope => 'public_profile', info_fields: 'id,first_name,last_name,link,email',
:display => 'popup',
:client_options => {:ssl => {:ca_file => '/usr/lib/ssl/certs/ca-certificates.crt'}}
end
Rails.application.config.middleware.use OmniAuth::Builder do
provider :google_oauth2, ENV['YT_CLIENT_ID'], ENV['YT_CLIENT_SECRET'],
scope: 'profile', image_aspect_ratio: 'square', image_size: 48,
# {name: "google_login", approval_prompt: ''},
access_type: 'online'
#ENV["GOOGLE_APP_ID"], ENV["GOOGLE_APP_SECRET"]
# {
# :name => "google",
# :scope => "userinfo.email, userinfo.profile, plus.me, http://gdata.youtube.com",
# :prompt => "select_account",
# :image_aspect_ratio => "square",
# :image_size => 50
# }
end
Rails.application.config.middleware.use OmniAuth::Builder do
if Rails.env == 'production'
key = ENV["LINKEDIN_PRODUCTION_KEY"]
secret = ENV["LINKEDIN_PRODUCTION_SECRET"]
else
key = "LINKEDIN_DEV_ID"
secret = "LINKEDIN_DEV_KEY"
end
provider :linkedin, key, secret,
:scope => "r_basicprofile r_emailaddress",
:field => ["id", "email-address", "first-name", "last-name" ],
:client_options => {:ssl => {:ca_file => '/usr/lib/ssl/certs/ca-certificates.crt'}}
end
In my new registration/session views, I have:
<% if devise_mapping.omniauthable? %>
<%= link_to icon('facebook', id: 'facebookauth'), user_omniauth_authorize_path(:facebook) %>
<%= link_to icon('google', id: 'googleauth'), user_omniauth_authorize_path(:google_oauth2) %>
<%= link_to icon('linkedin', id: 'linkedinauth'), user_omniauth_authorize_path(:linkedin) %>
<%= link_to icon('twitter', id: 'twitterauth'), user_omniauth_authorize_path(:twitter) %>
<% end %>
I think it has something to do with not having named strategies the authentications controller. In other tutorials, I have set up the following (now commented out of the controller because there is a method called apply_omniauth used now).
# def facebook
# # @user = User.find_for_facebook_oauth(request.env["omniauth.auth"])
# # if @user.persisted?
# # # @user.send_admin_mail
# # # @user.send_user_welcome_mail
# # sign_in @user, :event => :authentication #this will throw if @user is not activated
# # if @user.profile
# # redirect_to profile_path(@user.profile)
# # else
# # redirect_to new_profile_path
# # end
# # # sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
# # # set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
# # else
# # session["devise.facebook_data"] = request.env["omniauth.auth"]
# # redirect_to root_path
# # end
# # end
# # def linkedin
# # @user = User.find_for_linkedin_oauth(request.env["omniauth.auth"])
# # if @user.persisted?
# # # @user.send_admin_mail
# # # @user.send_user_welcome_mail
# # sign_in @user, :event => :authentication
# # if @user.profile
# # redirect_to profile_path(@user.profile)
# # else
# # redirect_to new_profile_path
# # end
# # # set_flash_message(:notice, :success, :kind => "LinkedIn") if is_navigational_format?
# # else
# # session["devise.linkedin_data"] = request.env["omniauth.auth"]
# # redirect_to root_path
# # end
# # end
# # def twitter
# # begin
# # @user = User.from_omniauth(request.env['omniauth.auth'])
# # session[:user_id] = @user.id
# # flash[:success] = "Welcome, #{@user.name}!"
# # rescue
# # flash[:warning] = "There was an error while trying to authenticate you..."
# # end
# # redirect_to new_profile_path #root_path
# # end
# # #
# def google_oauth2
# # You need to implement the method below in your model (e.g. app/models/user.rb)
# @user = User.find_for_google_oauth2(request.env["omniauth.auth"], current_user)
# if @user.persisted?
# sign_in @user, :event => :authentication #this will throw if @user is not activated
# if @user.profile
# redirect_to profile_path(@user.profile)
# flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google"
# else
# redirect_to new_profile_path
# end
# else
# session["devise.google_data"] = request.env["omniauth.auth"]
# redirect_to new_user_registration_url
# end
# end
Before I completely ditch the rails cast setup, is there a way I can point the current structure towards the named providers using the code I already have?
ANOTHER ATTEMPT:
So I ditched the RailsCast. I tried to follow this tutorial:
http://willschenk.com/setting-up-devise-with-twitter-and-facebook-and-other-omniauth-schemes-without-email-addresses/
I'm confused by the reference to adding a new 'class' called FormUser. I made a new model called form_user.rb and added the content as described. I'm using Rails 4. I don't know what atto-accessor means, but I have it in my file as demonstrated. I don't have a corresponding controller. I also don't have associations defined in my user model (which I think this belongs to).
Anyway, I have followed the setup and now get this error:
TypeError
superclass mismatch for class OmniauthCallbacksController
It's the same for each of the strategies defined in my app.
Has anyone seen this particular error & have any tips for how to resolve it?
The only difference between my setup and the tutorial is that in my controllers, I have a folder called users, in that, I have a registrations controller and an omniauth_callbacks controller. My routes have been adjusted to reflect this layer.
devise_for :users, class_name: 'FormUser',
:controllers => {
:registrations => "users/registrations",
# :omniauth_callbacks => "users/authentications"
:omniauth_callbacks => 'users/omniauth_callbacks',
}
get '/auth/:provider/callback' => 'users/authentications#create'
get '/authentications/sign_out', :to => 'users/authentications#destroy'
devise_scope :user do
get '/users/auth/:provider/upgrade' => 'users/omniauth_callbacks#upgrade', as: :user_omniauth_upgrade
get '/users/auth/:provider/setup', :to => 'users/omniauth_callbacks#setup'
end
If anyone else is tearing their hair out trying to figure this out - I don't have the answers for how to do it, but I do know that the Railscasts are so old they are not useful. There are several parts of the code above that no longer match the gem config. Following those tutorials will not help you. Over the past 1.5 years I've tried to follow at least 20 different tutorials and am yet to find one that I can get to work. Errors in the rails cast include the redirect (doesnt require reference to 'user' any more amongst many others. Give up if you're relying on the Rails Cast. I'd really appreciate if anyone has any insights into where to find a CURRENT tutorial.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With