0

私は Ruby on Rails にまったく慣れていないので、ご容赦ください。

ユーザーが Facebook からサインインできるようにしたい。railscast #265 Devise and OmniAuth (revised) に従いました。Railscast では、ユーザーは Facebook にログインする前に電子メールアドレスを求められます。事前にメールアドレスを必要とせずにFacebookからサインインできるようにしたい.

私が使っているもの: The Devise と Omniauth-facebook gems

私の期待: ユーザーがリンクをクリックし、Facebook からログインすると、Facebook がメール、名前、uid を返し、アプリがそれをデータベースに保存し、ユーザーが作成されます。

私が得るもの:エラーメッセージActiveRecord::StatementInvalid in OmniauthCallbacksController#facebook

SQLite3::ConstraintException: constraint failed: INSERT INTO "users" ("created_at", "current_sign_in_at", "current_sign_in_ip", "email", "encrypted_password", "last_sign_in_at", "last_sign_in_ip", "name", "provider", "remember_created_at", "reset_password_sent_at", "reset_password_token", "sign_in_count", "uid", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

これは私の user.rb モデルです:

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :token_authenticatable, :confirmable,
  # :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable, :omniauthable,
         :recoverable, :rememberable, :trackable, :validatable

  # Setup accessible (or protected) attributes for your model
  attr_accessible :email, :password, :password_confirmation, :remember_me
  # attr_accessible :title, :body

  # Nodig als :validatable uit is
  #validates_presence_of   :email, :if => :email_required?
  #validates_uniqueness_of :email, :allow_blank => true, :if => :email_changed?
  #validates_format_of     :email, :with  => Devise.email_regexp, :allow_blank => true, :if => :email_changed?
  #
  #validates_presence_of     :password, :if => :password_required?
  #validates_confirmation_of :password, :if => :password_required?
  #validates_length_of       :password, :within => Devise.password_length, :allow_blank => true


  def self.from_omniauth(auth)
    where(auth.slice(:provider, :uid)).first_or_create do |user|
      user.provider = auth.provider
      user.uid = auth.uid
      user.email = auth.email
      user.name = auth.info.name
    end
  end

  def self.new_with_session(params, session)
    if session["devise.user_attributes"]
      new(session["devise.user_attributes"], without_protection: true) do |user|
        user.attributes = params
        user.valid?
      end
    else
      super
    end
  end

  def email_required?
    provider == :facebook
  end

  def password_required?
    super && provider.blank?
  end

  def update_with_password(params, *options)
    if encrypted_password.blank?
      update_attributes(params, *options)
    else
      super
    end
  end

end

これは、ユーザーに OmniAuth を追加するための私の移行です (ユーザーは既にメールを持っています)

class AddOmniauthToUsers < ActiveRecord::Migration
  def change
    add_column :users, :provider, :string
    add_column :users, :uid, :string
    add_column :users, :name, :string
  end
end

そして、これは私の OmniAuth Callback コントローラーです:

class OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def all
      user = User.from_omniauth(request.env["omniauth.auth"])
      if user.persisted?
        flash.notice = "Loged in!"
        sign_in_and_redirect user
      else
        session["devise.user_attributes"] = user.attributes
        redirect_to new_user_registration_url
      end
    end
    alias_method :facebook, :all  
end

前もって感謝します

編集:スタックトレース:

app/models/user.rb:23:in `from_omniauth'
app/controllers/omniauth_callbacks_controller.rb:3:in `all'

編集:サーバーログ奇妙なことです。印刷するauthと、サーバーログに名前、電子メール、プロバイダー、および uid が表示されます。ただし、次のように表示されます。

INSERT INTO "users" ("created_at", "current_sign_in_at", "current_sign_in_ip", "email", "encrypted_password", "last_sign_in_at", "last_sign_in_ip", "name", "provider", "remember_created_at", "reset_password_sent_at", "reset_password_token", "sign_in_count", "uid", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)  [["created_at", Tue, 26 Feb 2013 17:20:23 UTC +00:00], ["current_sign_in_at", nil], ["current_sign_in_ip", nil], ["email", nil], ["encrypted_password", ""], ["last_sign_in_at", nil], ["last_sign_in_ip", nil], ["name", nil], ["provider", "facebook"], ["remember_created_at", nil], ["reset_password_sent_at", nil], ["reset_password_token", nil], ["sign_in_count", 0], ["uid", "XXXXX"], ["updated_at", Tue, 26 Feb 2013 17:20:23 UTC +00:00]]
SQLite3::ConstraintException: constraint failed: INSERT INTO "users" ("created_at", "current_sign_in_at", "current_sign_in_ip", "email", "encrypted_password", "last_sign_in_at", "last_sign_in_ip", "name", "provider", "remember_created_at", "reset_password_sent_at", "reset_password_token", "sign_in_count", "uid", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

たとえば、名前、電子メールですnilが、プロバイダーと uid (現在は XXXXX) が入力されています。ユーザー モデルに名前と電子メールを追加しました。多分ここに問題がありますか?これは役に立ちますか?

4

2 に答える 2

1

私が入れるたびにp auth.info.email(追加する必要がある多くのもののために.info)、サーバーログに電子メールアドレスが表示されます。

User モデルを変更したことが関係しています。

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

エラーはなくなりました。user.save!私はに変更したと追加しauth.info.email、に置き換えfirst_or_createましたfirst_or_initialize.tap

そのため、コンソール ( User.all) を見ると、電子メール、名前、uid、およびプロバイダーがデータベースにあります。

どうやらすべてがうまくいくようになりました。戦車はあなたの助けに害を与えます!

ps: サーバー ログには引き続き疑問符が表示されますが、データはレコードに保存されます。

于 2013-02-28T18:44:57.970 に答える
0

必須フィールドをすべて指定せずにユーザーを作成しようとするか、すでに存在するユーザーを作成しようとしていると思います (メールには一意性の制約があると思われます)。

後者を排除するには; users テーブルからすべてのユーザーを削除します。

前者をテストするには; User.create(some_params)メソッドに与えているのと同じパラメーターでユーザーを作成してみてくださいfrom_omniauth。これらを把握するには、pryのようなものを使用するか、単純に次のようにします。

def self.from_omniauth(auth)
    p auth # Add this line and watch the logs.
    ....
end

あなたのdb/schema.rb(またはdb/structure.sql実行した後rake db:structure:dump)を見て、NOT NULLまたはUNIQUE制約があるかどうかを確認することも役立つかもしれません。

于 2013-02-26T15:49:08.567 に答える