[英]Omniauth Twitter - Redirect to form for extra Information
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. 我正在按照本教程进行操作,但是当用户使用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: 在我的Omniauth回调控制器中,我有:
def after_sign_in_path_for(resource)
if resource.profile_valid?
super resource
else
finish_signup_path(resource
end
end
profile_valid checks for: profile_valid检查以下内容:
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). Twitter身份验证没有给您发送电子邮件,我需要注册才能通过电子邮件发送,因此我要传递带有正则表达式(TEMP_EMAIL_REGEX)的虚拟电子邮件。
So when a valid email isn't present it should redirect to the finish_signup_page which contains: 因此,当没有有效的电子邮件时,应将其重定向到包含以下内容的finish_signup_page:
<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
. 因此,我们基本上将提供者的数据存储在单独的模型
Social Provider
。
- sp = Social Provider is created
sp =社会提供者已创建
- 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.
我们将sp id存储在会话中,以将其与用户隔离。
- we render device registration/new view (adding all fields we need).
我们呈现设备注册/新视图(添加我们需要的所有字段)。
- On successful registeration, we link the sp to the created user.
成功注册后,我们将sp链接到创建的用户。
update_from_oauth
method, which updates the main attributes in the user without saving it. update_from_oauth
类具有update_from_oauth
方法,该方法将更新用户中的主要属性而不保存它。 ##########################
# 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.