Devise Omniauth - setup & defining strategies - ruby-on-rails
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.
Related
LoadError in OmniauthCallbacksController#passthru (with devise/stripe connect)
Trying to implement Stripe Connect, and am getting the following error when I click the "connect to stripe" button. The action 'passthru' could not be found for OmniauthCallbacksController users/omniauth_callbacks_controller.rb class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController def stripe_connect #user = current_user if #user.update_attributes({ provider: request.env["omniauth.auth"].provider, uid: request.env["omniauth.auth"].uid, access_code: request.env["omniauth.auth"].credentials.token, publishable_key: request.env["omniauth.auth"].info.stripe_publishable_key }) # anything else you need to do in response.. sign_in_and_redirect #user, :event => :authentication set_flash_message(:notice, :success, :kind => "Stripe") if is_navigational_format? else session["devise.stripe_connect_data"] = request.env["omniauth.auth"] redirect_to new_user_registration_url end end end models/user.rb devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :omniauth_providers => [:stripe_connect] routes.rb devise_for :users, controllers: { registrations: 'users/registrations', :omniauth_callbacks => "users/omniauth_callbacks" } gemfile.rb gem 'omniauth-stripe-connect' initializers/stripe.rb Rails.configuration.stripe = { :publishable_key => ENV['PUBLISHABLE_KEY'], :secret_key => ENV['SECRET_KEY'] } Stripe.api_key = Rails.configuration.stripe[:secret_key] initializers/devise.rb config.omniauth :stripe_connect, ENV['STRIPE_CONNECT_CLIENT_ID'], ENV['STRIPE_SECRET_KEY'], :scope => 'read_write', :stripe_landing => 'register' button link: <%= link_to image_tag('blue-on-light.png'), user_stripe_connect_omniauth_authorize_path(:stripe_connect) %> As I understand it with my noob Ruby mind, I need to define 'passthru'? how do I define it though? when I enter: def passthru end the link doesn't work / the page reloads itself. Haven't been able to find a solution on here. What am I missing? EDIT: Changed my connect to stripe link to: <%= link_to image_tag('blue-on-light.png'), "/users/auth/stripe_connect" %> The link takes me to the connect to stripe page, but when I click the "connect to stripe" button, the page cant be found, and doesn't load or redirect.
Can you try changing # app/controllers/omniauth_callbacks_controller.rb class OmniauthCallbacksController < ApplicationController def stripe_connect .... to class OmniauthCallbacksController < Devise::OmniauthCallbacksController def stripe_connect #user = User.find_for_stripe_connect(request.env['omniauth.auth'], current_user) set_notice_and_redirect end private def set_notice_and_redirect if #user.persisted? flash[:notice] = 'Successfully signed in' set_flash_message(:notice, :success, :kind => "Stripe") if is_navigational_format? else session["devise.stripe_connect_data"] = request.env["omniauth.auth"] redirect_to new_user_registration_url end end end and in your user model # Checks if user exists, otherwise create it def self.find_for_stripe_connect(access_token, _ = nil) data = access_token.info user = User.where(email: data['email']).first_or_create( email: data['email'], password: Devise.friendly_token[0, 20], provider: request.env["omniauth.auth"].provider, uid: request.env["omniauth.auth"].uid, access_code: request.env["omniauth.auth"].credentials.token, publishable_key: request.env["omniauth.auth"].info.stripe_publishable_key ) user end and also sing in path <%= link_to image_tag('blue-on-light.png'), user_stripe_connect_omniauth_authorize %> I think you don't need to define a passthru action. If you see the below two in the routes it can work. Authorize path is for redirecting user to stripe and callback is for redirecting user from stripe back to your site $ rake routes user_stripe_connect_omniauth_authorize /auth/stripe_connect(.:format) .... user_stripe_connect_omniauth_callback /auth/stripe_connect/callback(.:format) ....
Rails 4 - Devise Omniauth (multiple strategies)
I'm trying to make an app in Rails 4. I have been trying for the last 3 years (except for 10 days), to get devise to work. I'm trying to follow this tutorial: http://sourcey.com/rails-4-omniauth-using-devise-with-twitter-facebook-and-linkedin/ Please don't recommend other tutorials / gem documentation. I have tried at least 30 other tutorials and the gem documentation is full of errors and components that I don't understand. My current problem is that when I get to the finish sign up step in this tutorial, the form asks me for my email address. The users controller has a finish signup method as: def finish_signup # authorize! :update, #user if request.patch? && params[:user] #&& params[:user][:email] if #user.update(user_params) #user.skip_reconfirmation! # sign_in(#user, :bypass => true) # redirect_to root_path, notice: 'Your profile was successfully updated.' # redirect_to [#user, #user.profile || #user.build_profile] sign_in_and_redirect(#user, :bypass => true) else #show_errors = true end end end When I try this, I get this error: undefined method `match' for {:host=>"localhost", :port=>3000}:Hash The error points at this line: <div class="intpol3"><%= link_to 'Confirm my account', confirmation_url(#resource, confirmation_token: #token) %></div> My development environment is set up to include all the config details for my email sender. When I try the same step in production mode, I get this error: ActionView::Template::Error (No route matches {:action=>"show", :controller=>"profiles", :id=>nil} missing required keys: [:id]): It's looking for a profile id because I have an after_create action in my user model as: after_create :gen_profile def gen_profile Profile.create(user: self) # Associations must be defined correctly for this syntax, avoids using ID's directly. # Profile.save end My other issue with this tutorial is that the fields in the identity table aren't being populated. I'd love to find someone that has successfully implemented this tutorial or can see how to make this work. My code is: gemfile gem 'devise', '3.4.1' gem 'devise_zxcvbn' gem 'omniauth' gem 'omniauth-oauth2', '1.3.1' gem 'omniauth-google-oauth2' gem 'omniauth-facebook' gem 'omniauth-twitter' gem 'omniauth-linkedin-oauth2' gem 'google-api-client', require: 'google/api_client' routes 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' # PER SOURCEY TUTORIAL ---------- match '/users/:id/finish_signup' => 'users#finish_signup', via: [:get, :patch], :as => :finish_signup resources :users do resources :profiles, only: [:new, :create] end user.rb class User < ActiveRecord::Base TEMP_EMAIL_PREFIX = 'change#me' TEMP_EMAIL_REGEX = /\Achange#me/ devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :confirmable, :lockable, # :zxcvbnable, :omniauthable, :omniauth_providers => [:facebook, :linkedin, :twitter, :google_oauth2 ] # --------------- associations has_many :authentications, :dependent => :delete_all has_one :profile has_many :identities # --------------- scopes # --------------- validations # validates_presence_of :first_name, :last_name validates_uniqueness_of :email # per sourcey tutorial - how do i confirm email registrations are unique? # this is generating an error about the options in the without function -- cant figure out the solution validates_format_of :email, :without => TEMP_EMAIL_REGEX, on: :update # --------------- class methods # sourcey tutorial def self.find_for_oauth(auth, signed_in_resource = nil) # Get the identity and user if they exist identity = Identity.find_for_oauth(auth) # If a signed_in_resource is provided it always overrides the existing user # to prevent the identity being locked with accidentally created accounts. # Note that this may leave zombie accounts (with no associated identity) which # can be cleaned up at a later date. user = signed_in_resource ? signed_in_resource : identity.user # p '11111' # Create the user if needed if user.nil? # p 22222 # Get the existing user by email if the provider gives us a verified email. # If no verified email was provided we assign a temporary email and ask the # user to verify it on the next step via UsersController.finish_signup email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email) email = auth.info.email if email_is_verified # take out this if stmt for chin yi's solution user = User.where(:email => email).first if email # Create the user if it's a new registration if user.nil? # p 33333 user = User.new( # at least one problem with this is that each provider uses different terms to desribe first name/last name/email. See notes on linkedin above first_name: auth.info.first_name, last_name: auth.info.last_name, email: email ? email : "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com", #username: auth.info.nickname || auth.uid, password: Devise.friendly_token[0,20]) # fallback for name fields - add nickname to user table # debugger # if email_is_verified user.skip_confirmation! # end # user.skip_confirmation! user.save! end end # Associate the identity with the user if needed if identity.user != user identity.user = user identity.save! end user end def email_verified? self.email && TEMP_EMAIL_REGEX !~ self.email end users controller class UsersController < ApplicationController before_action :set_user, only: [:index, :show, :edit, :update, :finish_signup, :destroy] # i added finish_signup to the set_user action (not shown in tutorial) def index # if params[:approved] == "false" # #users = User.find_all_by_approved(false) # else #users = User.all # end end # GET /users/:id.:format def show # authorize! :read, #user end # GET /users/:id/edit def edit # authorize! :update, #user end # PATCH/PUT /users/:id.:format def update # authorize! :update, #user respond_to do |format| if #user.update(user_params) sign_in(#user == current_user ? #user : current_user, :bypass => true) format.html { redirect_to #user, notice: 'Your profile was successfully updated.' } format.json { head :no_content } else format.html { render action: 'edit' } format.json { render json: #user.errors, status: :unprocessable_entity } end end end # GET/PATCH /users/:id/finish_signup def finish_signup # authorize! :update, #user if request.patch? && params[:user] #&& params[:user][:email] if #user.update(user_params) #user.skip_reconfirmation! # sign_in(#user, :bypass => true) # redirect_to root_path, notice: 'Your profile was successfully updated.' # redirect_to [#user, #user.profile || #user.build_profile] sign_in_and_redirect(#user, :bypass => true) else #show_errors = true end end end # DELETE /users/:id.:format def destroy # authorize! :delete, #user #user.destroy respond_to do |format| format.html { redirect_to root_url } format.json { head :no_content } end end private def set_user #user = User.find(params[:id]) end def user_params # params.require(:user).permit(policy(#user).permitted_attributes) accessible = [ :first_name, :last_name, :email, :avatar ] # extend with your own params accessible << [ :password, :password_confirmation ] unless params[:user][:password].blank? # accessible << [:approved] if user.admin params.require(:user).permit(accessible) end end omniauth callbacks controller class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController def self.provides_callback_for(provider) class_eval %Q{ def #{provider} #user = User.find_for_oauth(env["omniauth.auth"], current_user) if #user.persisted? sign_in_and_redirect #user, event: :authentication set_flash_message(:notice, :success, kind: "#{provider}".capitalize) if is_navigational_format? else session["devise.#{provider}_data"] = env["omniauth.auth"] redirect_to new_user_registration_url end end } end # , current_user has been deleted from the end of line 51 #come back to put current_user into fidn by oauth so i can link other accounts - i have added this back for the purpose of solving the current problem # puts current_user.inspect # sign_in_and_redirect [#user, #user.profile || #user.build_profile] # sign_in_and_redirect_user(:user, event: :authentication) [:twitter, :facebook, :linkedin, :google_oauth2].each do |provider| provides_callback_for provider end def after_sign_in_path_for(resource) if resource.email_verified? super resource else finish_signup_path(resource) end end end registrations controller class Users::RegistrationsController < Devise::RegistrationsController protected def after_sign_up_path_for(resource) profile_path(resource) end private def user_params params.require(:user).permit(:first_name, :last_name, :email, :password ) end end Identity.rb class Identity < ActiveRecord::Base belongs_to :user validates_presence_of :uid, :provider validates_uniqueness_of :uid, :scope => :provider def self.find_for_oauth(auth) find_or_create_by(uid: auth.uid, provider: auth.provider) end end Identities controller class IdentitiesController < ApplicationController before_action :set_identity, only: [:show, :edit, :update, :destroy] before_action :authenticate_user! # GET /identities # GET /identities.json def index #identities = Identity.all end # GET /identities/1 # GET /identities/1.json def show end # GET /identities/new def new #identity = Identity.new end # GET /identities/1/edit def edit end # POST /identities # POST /identities.json def create #identity = Identity.new(identity_params) respond_to do |format| if #identity.save format.html { redirect_to #identity, notice: 'Identity was successfully created.' } format.json { render :show, status: :created, location: #identity } else format.html { render :new } format.json { render json: #identity.errors, status: :unprocessable_entity } end end end # PATCH/PUT /identities/1 # PATCH/PUT /identities/1.json def update respond_to do |format| if #identity.update(identity_params) format.html { redirect_to #identity, notice: 'Identity was successfully updated.' } format.json { render :show, status: :ok, location: #identity } else format.html { render :edit } format.json { render json: #identity.errors, status: :unprocessable_entity } end end end # DELETE /identities/1 # DELETE /identities/1.json def destroy #identity.destroy respond_to do |format| format.html { redirect_to identities_url, notice: 'Identity was successfully destroyed.' } format.json { head :no_content } end end private # Use callbacks to share common setup or constraints between actions. def set_identity #identity = Identity.find(params[:id]) end # Never trust parameters from the scary internet, only allow the white list through. def identity_params params[:identity] end end devise mailer - confirmation <div class="intpol3"><%= link_to 'Confirm my account', confirmation_url(#resource, confirmation_token: #token) %></div> SUMMARY OF CURRENT PROBLEMS: In development mode: There is a problem with the link to the confirmation token. I can't find any materials that indicate why this might arise. The error is:(ActionView::Template::Error (undefined method `match' for {:host=>"localhost", :port=>3000}:Hash): In production mode, there is an error with user looking for profile id. The error message is: ActionView::Template::Error (No route matches {:action=>"show", :controller=>"profiles", :id=>nil} missing required keys: [:id]): My profiles routes are: resources :profiles, only: [:show, :edit, :update, :destroy] resources :users do resources :profiles, only: [:new, :create] end None of the fields in the identity model are populating. They are all showing as nil. THINGS DONE DIFFERENTLY THAN AS SHOWN IN THE TUTORIAL: I also allow email sign up I add 'finish_sign_up' to the set_user before action in the users controller I add g+ strategy (which means my gems are slightly different) My new user method does not use raw info. It uses oauth processed info. My redirect in the finish sign up method is slightly different, although I've commented that out and gone back to the way it is set out in the tutorial to try to get this working (although the above problems are repeating). I'm going crazy trying to solve these problems. I'd say 3 years is way too long to be stuck on this problem. If anyone can help, I'd pay it forward 10x and then some. Thank you.
<div class="intpol3"><%= link_to 'Confirm my account', confirmation_url(#resource, confirmation_token: #token) %></div> Try resource instead of #resource. AFAIK it's only a helper_method, NOT an instance variable. I think that will solve your problem fully in production. Since #resource is not the same as resource, it hasn't been set, and you're basically calling confirmation_url(nil, confirmation_token: #token), and that nil is getting passed through to the error message. In development, there appears to be an additional issue, which most probably has to do with how you've configured config.action_mailer.default_url_options in config/environments/development.rb and most likely is raising the exception in ActionDispatch::Http::Url.build_host_url. I suspect you have something like: config.action_mailer.default_url_options[:host] = { host: 'localhost', port: 9000 } Change that to: config.action_mailer.default_url_options[:host] = 'localhost:9000' And see if that solves everything. If I'm wrong about how config.action_mailer.default_url_options is configured, please paste your config/environments/development.rb AND a full stack trace from your development error so we can help you further.
I defined a controller method for google_oauth2 for devise, but it's still missing
When I try to authenticate, I get the message: "Not found. Authentication passthru." I added an action_missing method to get a clue: when it's called, it logs: Parameters: {"provider"=>"google_oauth2"} So it would appear that I'm getting a complaint that I'm missing the very method that I've defined. Why is my action missing when it's defined? class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController def google_oauth2 #user = User.from_omniauth(request.env["omniauth.auth"]) if #user.persisted? flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google" sign_in_and_redirect #user, :event => :authentication else session["devise.google_data"] = request.env["omniauth.auth"] redirect_to new_user_registration_url end end def action_missing(provider) logger.debug provider end end devise.rb: config.omniauth :google_oauth2, 'my', 'secret', { :name => "google", :scope => 'email, profile', :prompt => 'select_account', :image_aspect_ratio => 'square', :image_size => 50 } User.rb: class User < ActiveRecord::Base devise :omniauthable, :omniauth_providers => [:google_oauth2] def self.from_omniauth(access_token) data = access_token.info user = User.where(:email => data["email"]).first # Uncomment the section below if you want users to be created if they don't exist # unless user # user = User.create(name: data["name"], # email: data["email"], # password: Devise.friendly_token[0,20] # ) # end user end end
If you provide :name to your config settings you have to call it from the given name. Also your Authorized redirect URIs will have the name "google" as you specify here.
I found my mistake, someone else may find it edifying: in devise.rb, I had: { :name => 'google', <====== BAD IDEA! :scope => 'email, profile', :prompt => 'select_account', :image_aspect_ratio => 'square', :image_size => 50 } the first item, the :name, was copied from another omniauth tutorial. It seems to be a very bad idea. Removing it made things go.
Using devise to authenticate a API login request via JSON
I'm trying to use devise to authenticate a simple email/password login so users can access the rest of the API via auth tokens. I'm running into trouble with devise simply returning You need to sign in or sign up before continuing. Here's my code: class LoginController < ApplicationController respond_to :json def login resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure") render :status => 200, :json => { :success => true, :info => "Logged in", :user => current_user } end def failure render :status => 401, :json => { :success => false, :info => "Login Failed", :data => {} } end def resource_name :user end def resource #resource ||= User.new end def devise_mapping #devise_mapping ||= Devise.mappings[:user] end end routes.rb devise_scope :user do post 'register' => 'registration#create', :as => :registers post 'login' => 'login#login', :as => :login end I'm sending the following post data: { "user" : { "email" : "testPost4#fake.com", "password" : "Password1" } } Having browsed various posts I've added: config.navigational_formats = [:json] to the devise.rb file but it didn't solve the problem. Adding skip_before_filter :authenticate_user! doesn't work either.
I wasn't able to get this working so I have reverted to the much simpler approach of checking and signing in manually. def login params = login_params user = User.find_by_email(params['email'].downcase) if user.valid_password?(params['password']) then sign_in(user) success else failure end end
Google+ Sign Up with Devise and Rails (google_oauth2)
I'm getting the following error when trying to sign in through google+ using the google_oauth2 gem. undefined method `find_for_google_oauth2' for #<Class:0x007ff70a337148> Here's the three files I've altered for sign up. user.rb def google_oauth2 user = User.from_omniauth(request.env["omniauth.auth"]) if user.persisted? flash.notice = "Signed in Through Google!" sign_in_and_redirect user else session["devise.user_attributes"] = user.attributes flash.notice = "You are almost Done! Please provide a password to finish setting up your account" redirect_to new_user_registration_url end end omniauth_callbacks_controller.rb 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? flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google" sign_in_and_redirect #user, :event => :authentication else session["devise.google_data"] = request.env["omniauth.auth"] redirect_to new_user_registration_url end end and I've added config.omniauth :google_oauth2 in my devise.rb file. routes.rb devise_for :users, :controllers => { :registrations => "registrations", :sessions => "sessions", :omniauth_callbacks => "users/omniauth_callbacks" }
You are calling find_for_google_oauth2 from the omniauth_callbacks_controller, but you are using the wrong method name google_oauth2. You should replace google_oauth2 with find_for_google_oauth2. And it seems like the code in user.rb is incorrect because it contains the controller code. Do you see it looks exactly the same like your controller code? :) Correct code for user.rb def self.find_for_google_oauth2(access_token, signed_in_resource=nil) data = access_token.info user = User.where(:email => data["email"]).first # Uncomment the section below if you want users to be created if they don't exist # unless user # user = User.create(name: data["name"], # email: data["email"], # password: Devise.friendly_token[0,20] # ) # end user end Read more here: https://github.com/zquestz/omniauth-google-oauth2#devise