I'm following this tutorial but fail on how to redirect the User to a page to fill out more information when he connects with omniauth.
In my User Model I have:
user = User.new(
name: auth.extra.raw_info.name,
user_name: auth.info.nickname,
about_me: auth.info.description,
email: email ? email : "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com",
password: Devise.friendly_token[0,20]
)
user.skip_confirmation!
user.save!
In my Omniauth callbacks controller I have:
def after_sign_in_path_for(resource)
if resource.profile_valid?
super resource
else
finish_signup_path(resource
end
end
profile_valid checks for:
def profile_valid?
self.email && self.email !~ TEMP_EMAIL_REGEX
end
Twitter auth doesn't give you an email, which I require for a Registration, so i'm passing a dummy email with a regex (TEMP_EMAIL_REGEX).
So when a valid email isn't present it should redirect to the finish_signup_page which contains:
<div id="add-email" class="container">
<h1>Add Email</h1>
<%= form_for(current_user, :as => 'user', :url => finish_signup_path(current_user), :html => { role: 'form'}) do |f| %>
<% if @show_errors && current_user.errors.any? %>
<div id="error_explanation">
<% current_user.errors.full_messages.each do |msg| %>
<%= msg %><br>
<% end %>
</div>
<% end %>
<!-- User Name -->
<div class="form-group">
<%= f.label :user_name %>
<div class="controls">
<%= f.text_field :user_name, :autofocus => true, :value => '', class: 'form-control', placeholder: 'Username' %>
<p class="help-block">Please enter your username</p>
</div>
</div>
<div class="form-group">
<%= f.label :email %>
<div class="controls">
<%= f.text_field :email, :autofocus => true, :value => '', class: 'form-control', placeholder: 'Example: email@me.com' %>
<p class="help-block">Please confirm your email address. No spam.</p>
</div>
</div>
<div class="actions">
<%= f.submit 'Continue', :class => 'btn btn-primary' %>
</div>
<% end %>
</div>
Here is my problem, when I enter something it doesn't save the User and it would be better if in the actual fields the current values would be present?
But I'm lost on how to do that, or maybe I'm trying this now for too long and have a tunnel-vision.
What am I Missing?
First go through the following classes. You need to store the correct data for the user, a generated email is not a good solution. So we basically store the provider's data in a separate model Social Provider
.
- sp = Social Provider is created
- The user is initialized by the data received from the provider (not saved).
- We store the sp id in the session, to isolate it from the user reach.
- we render device registration/new view (adding all fields we need).
- On successful registeration, we link the sp to the created user.
update_from_oauth
method, which updates the main attributes in the user without saving it. ##########################
# User Class
##########################
class User < ActiveRecord::Base
has_many :social_providers, dependent: :destroy
# update from OAuth
def update_from_oauth(auth, provider_type)
self.email = auth[:info][:email] if self.email.blank?
case provider_type
when :twitter
name = auth[:info][:name].split(' ')
self.first_name ||= name[0]
self.last_name ||= name[1]
self.remote_avatar_url = auth[:extra][:raw_info][:profile_image_url]
when :facebook
...
when :google
...
end
end
end
class SocialProvider < ActiveRecord::Base
#Relations
belongs_to :user
def self.find_for_oauth(auth, provider_type)
unless social_provider = self.find_by(pid: auth[:uid].to_s, provider_type: provider_type)
user = User.find_by_email(auth[:info][:email])
social_provider = user.social_providers.where(provider_type: provider_type).first if user.present?
social_provider ||= SocialProvider.new
end
social_provider.update_from_oauth(auth, provider_type)
social_provider
end
def update_from_oauth(auth, provider_type)
self.email= auth[:info][:email]
self.pid= auth[:uid]
self.provider_type= provider_type
credentials = auth[:credentials]
case provider_type
when :twitter
self.token = credentials[:token]
self.secret = credentials[:secret]
self.url = auth[:info][:urls][:Twitter]
when :facebook
...
when :google
...
end
end
end
##########################
# SocialProvider Migration
##########################
class CreateSocialProviders < ActiveRecord::Migration
def change
create_table "social_providers" do |t|
t.string "pid" # user provider id
t.string "token"
t.string "refresh_token"
t.string "secret"
t.datetime "expires_at"
t.string "provider_type"
t.integer "user_id"
t.string "url"
t.string "email"
t.timestamps
end
end
end
###############################
# OmniAuth Callbacks Controller
###############################
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
before_filter :prepare_auth
def facebook
connect(:facebook)
end
def twitter
connect(:twitter)
end
def google_oauth2
connect(:google)
end
private
def prepare_auth
@auth = request.env["omniauth.auth"]
end
def connect(provider_type)
social_provider = SocialProvider.find_for_oauth(@auth, provider_type)
if user_signed_in?
if social_provider and social_provider.user_id == current_user.id
flash[:notice] = "Your #{provider_type} account is already attached"
redirect_to current_user and return
elsif social_provider.user_id.nil?
current_user.update_from_oauth(@auth, provider_type)
current_user.social_providers << social_provider if current_user.save
flash[:notice] = "Successfully attached #{provider_type} account"
redirect_to current_user and return
else
flash[:notice] = "#{provider_type} is already connected to another account"
redirect_to current_user and return
end
else
@user = social_provider.user || User.find_by_email(@auth[:info][:email]) || User.new
@user.update_from_oauth(@auth, provider_type)
social_provider.save
if @user.persisted? # If user already has account and not logged in
@user.social_providers << social_provider if @user.save
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => provider_type.capitalize
sign_in_and_redirect @user, :event => :authentication
else # If user has no account
session[:sp_id] = social_provider.id
render 'registrations/new'
end
end
end
end
#################################
# Devise::RegistrationsController
#################################
class RegistrationsController < Devise::RegistrationsController
def create
super
if user_signed_in? and session[:sp_id].present?
SocialProvider.find_by(id: session[:sp_id],user_id: nil).update(user_id: current_user.id)
end
end
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.