【问题标题】:Omniauth Twitter - Redirect to form for extra InformationOmniauth Twitter - 重定向以获取更多信息
【发布时间】:2015-01-26 15:01:18
【问题描述】:

我正在关注this tutorial,但在用户连接omniauth 时如何将用户重定向到一个页面以填写更多信息时失败。

在我的用户模型中,我有:

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!

在我的 Omniauth 回调控制器中,我有:

def after_sign_in_path_for(resource)
  if resource.profile_valid?
    super resource
  else
    finish_signup_path(resource        
  end
end

profile_valid 检查:

def profile_valid?
  self.email && self.email !~ TEMP_EMAIL_REGEX
end

Twitter auth 不会给你一封电子邮件,这是我注册时需要的,所以我传递了一封带有正则表达式 (TEMP_EMAIL_REGEX) 的虚拟电子邮件。

因此,当一个有效的电子邮件不存在时,它应该重定向到包含:

<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>

这是我的问题,当我输入一些内容时,它不会保存用户,如果在实际字段中存在当前值会更好?

但是我不知道如何做到这一点,或者我现在尝试这个太久了并且有一个隧道视野。

我错过了什么?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 devise omniauth twitter-oauth


    【解决方案1】:

    首先完成以下课程。您需要为用户存储正确的数据,生成的电子邮件不是一个好的解决方案。所以我们基本上将提供者的数据存储在一个单独的模型Social Provider

    注册流程:

    • sp = 已创建社交提供者
    • 用户由从提供程序接收的数据初始化(未保存)。
    • 我们将 sp id 存储在会话中,以将其与用户范围隔离。
    • 我们呈现设备注册/新视图(添加我们需要的所有字段)。
    • 注册成功后,我们将 sp 链接到创建的用户。

    1.User类,有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
    

    2。 SocialProvider 类或(身份)

    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
    

    3。 Omniauth 回调控制器

    ###############################
    # 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
    

    4。覆盖设计注册控制器

    #################################
    # 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
    

    【讨论】:

    猜你喜欢
    • 2013-04-01
    • 2016-11-11
    • 2018-02-09
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多