Rails Devise注册:如何通过Twitter API获取用户网站数据及提取expanded_url
如何通过Omniauth-Twitter + Devise获取Twitter用户的网站数据(含expanded_url提取)
刚好我之前在Rails项目里用Devise+Omniauth-Twitter实现过类似需求,给你一步步拆解怎么搞定:
一、先确认Omniauth-Twitter的基础配置
首先得确保你的Omniauth-Twitter有权限获取用户的网站相关数据。Twitter API v1.1里,用户的网站信息默认返回在entities字段里,只要你的API密钥正常,基本不用额外加scope。可以检查下config/initializers/devise.rb里的配置:
Devise.setup do |config| config.omniauth :twitter, ENV['TWITTER_API_KEY'], ENV['TWITTER_API_SECRET'], { secure_image_url: true, image_size: 'original' # 如果用API v2可能需要额外指定fields,但目前Omniauth-Twitter大多兼容v1.1,默认配置就够 } end
二、自定义Omniauth回调控制器处理数据
接下来要在回调逻辑里提取网站的expanded_url——因为Twitter返回的网站字段嵌套在类数组结构里,得针对性解析。
首先生成自定义的回调控制器:
rails generate devise:controllers users -c omniauth_callbacks
然后修改config/routes.rb让Devise使用这个自定义控制器:
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
打开生成的app/controllers/users/omniauth_callbacks_controller.rb,修改twitter方法:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController def twitter # 拿到Twitter返回的所有原始数据 auth = request.env['omniauth.auth'] # 重点:提取expanded_url # Twitter API返回的结构是:auth.extra.raw_info.entities.url.urls 是一个数组 # 一般用户只会填一个个人网站,所以取第一个元素的expanded_url即可 website_url = nil if auth.dig(:extra, :raw_info, :entities, :url, :urls).present? website_url = auth.extra.raw_info.entities.url.urls.first['expanded_url'] end # 查找或创建用户,把网站URL传进去 @user = User.from_omniauth(auth, website_url) if @user.persisted? sign_in_and_redirect @user, event: :authentication set_flash_message(:notice, :success, kind: 'Twitter') if is_navigational_format? else # 如果用户未保存成功(比如缺少邮箱),把数据存入session,跳转到注册页补充信息 session['devise.twitter_data'] = auth.except('extra') session['devise.twitter_website'] = website_url redirect_to new_user_registration_url end end def failure redirect_to root_path, alert: 'Twitter登录失败,请稍后重试~' end end
三、在User模型里处理用户创建/更新
接下来在User模型里实现from_omniauth方法,把提取到的网站URL存入用户表:
class User < ApplicationRecord devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:twitter] def self.from_omniauth(auth, website_url) # 先按provider和uid查找用户,找不到则创建 user = User.where(provider: auth.provider, uid: auth.uid).first_or_create do |user| # Twitter可能不返回邮箱,这里做兜底处理 user.email = auth.info.email || "#{auth.uid}@twitter.example.com" user.password = Devise.friendly_token[0, 20] user.name = auth.info.name user.nickname = auth.info.nickname user.website = website_url # 把提取到的网站URL存起来 # 需要头像的话可以加:user.avatar_url = auth.info.image end # 已经存在的用户如果未填写网站,也更新一下(可选) user.update(website: website_url) if user.website.blank? && website_url.present? user end end
四、添加数据库字段
最后,给users表加个website字段来存储这个URL:
rails generate migration AddWebsiteToUsers website:string rails db:migrate
一些小提醒
- 如果你用的是Twitter API v2,返回的结构可能略有不同,这时候可以在回调里打印
auth.inspect查看实际字段路径,再调整提取逻辑。 - 有些用户可能没设置个人网站,一定要做
present?判断,避免空指针报错。 - Twitter经常不返回用户邮箱,创建用户时要处理这种情况,要么生成虚拟邮箱,要么引导用户手动补充。
内容的提问来源于stack exchange,提问作者Designer
相关产品推荐
相关产品推荐

