【问题标题】:Getting (omniauth-facebook) and (omniauth-twitter) work让 (omniauth-facebook) 和 (omniauth-twitter) 工作
【发布时间】:2013-09-01 11:52:59
【问题描述】:

我正在使用:

  • Ruby on Rails 4
  • 设计 3.0.3
  • omniauth (1.1.4)
  • omniauth-facebook (1.4.1)
  • omniauth-twitter (1.0.0)

我最近设置了我的omniauth-facebook,一切正常。现在我想添加omniauth-twitter,但不知何故我把事情搞砸了,很糟糕。

1.) 为了设置我的Omniauth-Facebook,我这样做了(简而言之):

gem 'omniauth'
gem 'omniauth-facebook'

2.) 在我的用户模型中添加了“provider”和“uid”列。

3.) 接下来,我在 config/initializers/devise.rb 中声明了提供程序:

require "omniauth-facebook"
config.omniauth :facebook, "App_ID", "App_Secret",
                                {:scope => 'email,offline_access',
                                 :client_options => {:ssl => {:ca_file => 'lib/assets/cacert.pem'}},
                                 :strategy_class => OmniAuth::Strategies::Facebook}

4.) 我编辑了我的模型 User.rb

# Facebook Settings
def self.find_for_facebook_oauth(auth, signed_in_resource = nil)
    user = User.where(provider: auth.provider, uid: auth.uid).first
    if user.present?
        user
    else
        user = User.create(first_name:auth.extra.raw_info.first_name,
                                             last_name:auth.extra.raw_info.last_name,
                                             facebook_link:auth.extra.raw_info.link,
                                             user_name:auth.extra.raw_info.name,
                                             provider:auth.provider,
                                             uid:auth.uid,
                                             email:auth.info.email,
                                             password:Devise.friendly_token[0,20])
    end
end

并添加了要设计的属性:

:omniauth_providers => [:facebook]

5.) 我编辑了路线:

devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }

结局

虽然这对 Facebook 来说非常有效,但我现在尝试了几个小时才让它在 Twitter 上工作,但我就是想不通。

如果有这方面经验的人,或者只是知道解决方案的人可以帮助我进行设置,我将非常感激 :)

谢谢大家,很抱歉发了这么长的帖子。

另外

Twitter 不提供 :email 属性,所以我猜我必须拆分我的用户注册过程?

我的用户模型中的Twitter操作

# Twitter Settings
def self.find_for_twitter_oauth(auth, signed_in_resource=nil)
    user = User.where(:provider => auth[:provider], :uid => auth[:uid]).first
    unless user
        user = User.create(:first_name => auth[:name],
                                             :user_name => auth[:screen_name],
                                             :provider => auth[:provider], :uid => auth[:uid],
                                             :password => Devise.friendly_token[0,20]
        )
    end
    user
end

# build auth cookie hash for twitter
def self.build_twitter_auth_cookie_hash data
    {
        :provider => data.provider, :uid => data.uid.to_i,
        :access_token => data.credentials.token, :access_secret => data.credentials.secret,
        :first_name => data.name, :user_name => data.screen_name,

    }
end

我必须为用户迁移一个可确认的 -> How To: Add :confirmable to Users

我的表单的问题,(至少我现在要解决这个问题了 :))

【问题讨论】:

  • 如果您解释和/或显示您收到的实际错误,它总是有帮助的。而且,长帖子不是问题。信息越多越好。你的实际上比很多人都短。
  • 你能把devise.rb 推特的代码放上去
  • 如果你有其他 gem,你就不需要omniauth gem。

标签: ruby-on-rails facebook twitter oauth omniauth


【解决方案1】:

要解决您的电子邮件问题,您可以设置一个虚拟邮件,或添加第二步,让用户添加他/她的电子邮件。

虚拟邮件:

class User < ActiveRecord::Base

  before_create :set_dummy_mail, if self.provider == "twitter"

  private

  def set_dummy_mail
    self.email = "#{self.name}_email@example.com"
  end

end

或第二步选项:

如果提供商是 twitter 并且电子邮件为空白,则修改您的控制器以重定向到添加电子邮件步骤。如果提供商是 twitter,也许您还必须修改您的验证以允许在创建电子邮件时为空白。

更新:我这样做了:

宝石文件:

gem "devise"
gem "omniauth"
gem "omniauth-facebook"
gem "omniauth-twitter"

我用过:

  • 设计版本 2.2.3
  • omniauth 1.1.4
  • omniauth-facebook 1.3.0
  • omniauth-twitter 0.0.17

如果您使用不同的版本,您可能必须更改一些内容..

routes.rb:

devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }

devise_scope :user do
  post "account/create" => "users/accounts#create"
end

app/models/user.rb

class User < ActiveRecord::Base

  # allow email blank for first create
  validates_format_of :email, :with => Devise.email_regexp, :allow_blank => true, :if => :email_changed?

  # facebook find method
  def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
    user = User.where(:provider => auth.provider, :uid => auth.uid).first
    unless user
      user = User.create(:first_name => auth.extra.raw_info.first_name, 
                         :last_name => auth.extra.raw_info.last_name, 
                         :facebook_link => auth.extra.raw_info.link, 
                         :user_name => auth.extra.raw_info.name
                         :provider => auth.provider, 
                         :uid => auth.uid, :email => auth.info.email, 
                         :password => Devise.friendly_token[0,20]
                        )
      user.confirm!
    end
    user
  end

  # twitter find method
  def self.find_for_twitter_oauth(auth, signed_in_resource=nil)
    user = User.where(:provider => auth[:provider], :uid => auth[:uid]).first
    unless user
      user = User.create(:first_name => auth[:first_name], :user_name => auth[:user_name],
                         :provider => auth[:provider], :uid => auth[:uid], 
                         :password => Devise.friendly_token[0,20]
                        )
    end
    user
  end

  # build auth cookie hash for twitter
  def self.build_twitter_auth_cookie_hash data
    {
      :provider => data.provider, :uid => data.uid.to_i,
      :access_token => data.credentials.token, :access_secret => data.credentials.secret,
      :first_name => data.screen_name, :user_name => data.name,

    }
  end

end

app/controllers/users/omniauth_callbacks_controller.rb

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

  # callback action for facebook auth
  def facebook
    @user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)

    if @user.persisted?
      sign_in_and_redirect @user, :event => :authentication
      set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end

  # callback action for twitter auth
  def twitter
    data = session["devise.omniauth_data"] = User.build_twitter_auth_cookie_hash(request.env["omniauth.auth"])

    user = User.find_for_twitter_oauth(data)
    if user.confirmed? # already registered, login automatically
      flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Twitter"
      sign_in_and_redirect user, :event => :authentication
    elsif !user.email?
      flash[:error] = "You must add an email to complete your registration."
      @user = user
      render :add_email
    else
      flash[:notice] = "Please confirm your email first to continue."
      redirect_to new_user_confirmation_path
    end
  end

end

app/views/users/omniauth_callbacks/add_email.html.erb

<%= form_for(@user, :as => "user", :url => account_create_path, :html => {:class => "form-inline"}) do |f| %>
  <%= f.email_field :email, :placeholder => User.human_attribute_name(:email), :class => "input-medium" %>
  <%= f.submit "Finish registration", :class => "btn btn-small" %>
<% end %>

app/controllers/users/accounts_controller.rb

class Users::AccountsController < ApplicationController

  def create
    data = session["devise.omniauth_data"]
    data[:email] = params[:user][:email]
    user = User.find_for_twitter_oauth(data)
    user.email = data[:email]

    if user.save
      flash[:notice] = I18n.t "devise.registrations.signed_up_but_unconfirmed"
      redirect_to root_path
    else
      flash[:error] = I18n.t "devise.omniauth_callbacks.failure", :kind => data[:provider].titleize, :reason => user.errors.full_messages.first
      render "users/omniauth_callbacks/add_email"
    end
  end

end

也许您必须修改我的解决方案的一个或其他部分。您还可以重构用户模型中的两种方法(find_for_facebook_auth、find_for_twitter_auth)以使用一种动态方法。试试看,如果你还有问题,请告诉我。如果您发现任何拼写错误,也请告诉我。您还应该编写测试来检查系统中的所有内容。

【讨论】:

  • 嘿马特里克,我真的很喜欢你的方法。我做到了,并稍微更改了 Rails 4 和我的设计的代码。但是我在用户中总是出现 NoMethodError::OmniauthCallbacksController#twitter |未定义的方法“提供者”。你能看看我的 Github Repo 吗? -> github.com/Theminijohn/myapp
  • Ich bin hier ein bisschen überfordert :)
  • 你究竟是从哪里得到错误的?在哪条线上?你能发布堆栈跟踪吗?
  • 我更新了我的答案。查看 find_for_facebook_oauth、find_for_twitter_oauth 和 build_twitter_auth_cookie_hash 数据。build_twitter_auth_cookie_hash 生成一个哈希值。
  • 我得到错误:未定义的方法`确认?对于 #<0x490a070>
【解决方案2】:

在 gem 文件中添加这个

gem 'omniauth-twitter'

打包并重启服务器

在此之后在 config/initializer/devise.rb 中添加您的 app_id 和密钥

require "omniauth-twitter"
config.omniauth :twitter, "app_id", "secret_key"

编辑您的用户模型

:omniauth_providers => [:facebook,:twitter]
def self.find_for_twitter_oauth(auth, signed_in_resource=nil)

  user = User.where(:provider => auth.provider, :uid => auth.uid).first
  unless user
    user = User.create(name:auth.extra.raw_info.name,
                         provider:auth.provider,
                         uid:auth.uid,
                         email:auth.info.email,
                         password:Devise.friendly_token[0,20]                            
                         )

  end
  user
end

中添加新的控制器文件

app/controller/user/omniauth_callbacks_controller.rb

 def twitter
@user = User.find_for_twitter_oauth(request.env["omniauth.auth"], current_user)

if @user.persisted?
  sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
  set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
else
  session["devise.twitter_data"] = request.env["omniauth.auth"]
  redirect_to new_user_registration_url
end

结束

在您的视图文件中添加此链接

<%= link_to 'sign in with twitter', user_omniauth_authorize_path(:twitter) %>

用户模型所需的更改,因为 twitter 不返回用户的电子邮件 ID: 创建迁移文件以允许用户的电子邮件列中存在空值:

class ChangeEmailToNullInUser < ActiveRecord::Migration
  def up
      change_column :users, :email, :string, :null=>true
   end

  def down
  end
end

在此之后您还需要覆盖用户模型验证,因此将其添加到 user.rb 中

def email_required?
   false
end

注意:在执行此操作之前,您应该在 twitter 上创建您的应用程序并提供正确的回调路径。这很重要,因为在通过 twitter 进行身份验证后,控制器将返回到您在 twitter 上的应用程序中指定的路径。

如果您有任何问题,请告诉我。

【讨论】:

  • 嗨 Sagar,感谢您的帮助!我设置了所有内容,我通过 twitter 获得了连接,但我在 Users::OmniauthCallbacksController#twitter 中收到错误 ActionDispatch::Cookies::CookieOverflow#twitter
  • 我更新了关于如何克服 Cookie 溢出的问题。我想这是一个可行的解决方案,但请看一下。现在我有那些 twitter 属性错误:(
  • The Mini John 我回溯了这个问题。我之前遇到过的同样问题,主要原因是 Twitter 不返回用户电子邮件 ID(需要注意),其 twitter 的政策 API 旨在这样做,并且在我们的设计用户模型中,电子邮件是必填字段。我正在根据它更新我的答案,所以检查一下
  • 嘿 Sagar,感谢您的挖掘,但我真的需要在我的应用程序中使用该电子邮件属性 :( 我目前正在尝试上述 Matherick 的答案,但遇到了问题......
  • 好的,如果你想设置一个虚拟的电子邮件ID,那么你可以通过用户模型中的回调来设置它
【解决方案3】:

Mattherick 有一个很好的电子邮件解决方案,但我无法让 before_create 工作。回调不能与条件 if 语句配合使用,因为逗号后面的任何内容都是选项哈希。因此:

before_save :set_dummy_email, if self.provider == "twitter"

弹出我的错误。

我就是这样解决这个问题的:

before_save :set_dummy_email

def set_dummy_email
  self.email ||= "#{self.name}-CHANGEME@example.com"
end

这只会在提供商未提供电子邮件的情况下设置电子邮件(即:Twitter)。

然后对于设置属性的更“通用”方式(因此您不需要独特的策略:

def self.from_omniauth(auth)
  where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
    user.name = auth.info.name || auth.info.nickname
    user.provider = auth.provider
    user.uid = auth.uid
    user.email = auth.info.email if auth.info.email
    user.save
  end
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多