我尝试在我的网站ChercheAvocat(Rails 3)上安装FB Connect,但点击链接后#34;使用Facebook登录"我有一个错误"参数app_id是必需的"。 网址:https://www.facebook.com/dialog/oauth?client_id=&display=popup&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fcustomers%2Fauth%2Ffacebook%2Fcallback&response_type=code&scope=email&state=fbe0db878d8d47b896aa18f40e00d5f1e117dde9bef55de9
我在Developers.Facebook上创建了应用程序(Chercheavocat-login),我已将ID添加到代码中。
你能帮助我吗?
的routes.rb
ChercheAvocat::Application.routes.draw do
devise_for :customers, :controllers => {
:omniauth_callbacks => "customers/omniauth_callbacks"
}
root :to => 'home#index'
初始化/ devise.rb
require "omniauth-facebook"
Devise.setup do |config|
config.secret_key = 'xxxxxxxxx'
config.omniauth :facebook,
ENV['FACEBOOK_KEY'],
ENV['FACEBOOK_SECRET'],
:scope => 'email',
:display => 'popup',
:provider_ignores_state => true
视图/问题/ no_answers.html.erb
<script>
window.fbAsyncInit = function() {
FB.init({
appId : '1400942343542259',
xfbml : true,
version : 'v2.2'
});
};
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
</script>
模型/ customer.rb
require 'digest/sha1'
class Customer < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
MIN_PASSWORD_LENGTH = 6
MAX_PASSWORD_LENGTH = 32
SALT = '")cvvvvvv("f!dsqf!!rffffqf/qdddf+/79dddd54'
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :confirmable,
:omniauthable, :omniauth_providers => [:facebook]
validates_presence_of :civility, :first_name, :last_name, :email
validates :email, :email => true
validates_uniqueness_of :email
validates_confirmation_of :email
validates_presence_of :password, :on => :create
validates_length_of :password, :within => MIN_PASSWORD_LENGTH..MAX_PASSWORD_LENGTH
validates_confirmation_of :password
validates_presence_of :zip_code, :city, :on => :update
acts_as_mappable
acts_as_url :id_full_name, :sync_url => true # uses attributes :url
attr_accessor :password
has_many :contact_requests, :dependent => :nullify
has_many :questions, :dependent => :nullify
has_many :subscriptions, :dependent => :destroy
before_validation(:encrypt_password, :on => :create)
before_save :ensure_geolocation, :setup_modifications
after_create :sync_subs
before_update :check_sub_related_changes
after_update :sync_sub_related_changes
CIVILITIES_ORDERED = ['mr', 'mrs', 'miss']
scope :for_search, lambda { |params|
custom_scope = self.scoped
(params[:search] || '').split(/\s+/).each { |word|
custom_scope = custom_scope.where(
'first_name like ? or last_name like ? or email like ?',"%#{word}%", "%#{word}%", "%#{word}%"
)
}
custom_scope
}
def self.civilities(format = :short)
CIVILITIES_ORDERED.map { |code| [I18n.t(format, :scope => "civilities.#{code}"), code] }
end
[:short, :long].each do |code|
define_method "#{code}_civility" do
I18n.t(code, :scope => "civilities.#{civility}")
end
end
def full_name
"#{first_name.strip.titleize} #{last_name.strip.titleize}"
end
def id_full_name
"#{id}-#{full_name}".to_url
end
def to_param
url
end
def geolocated?
lat.present? && lng.present?
end
def greeting_name
"#{short_civility} #{last_name.strip.titleize}"
end
def has_sub?(kind)
subscriptions.kind(kind).count > 0
end
def obfuscation
[long_civility, last_name.present? && "#{last_name.strip[0, 1].mb_chars.upcase}." || nil].compact.join(' ')
end
# Set a new activation_code to persist password until email sent
def regenerate_password!
self.password = self.class.random_pronouncable_password
save(validate: false)
end
def result_name
"#{short_civility} #{last_name.titleize}"
end
# Designed to be used from customer forms (either back or authenticated front).
# kinds is a complete list of subscribed kinds.
# DEV NOTE: this impacts the DB immediately and may raise AR exceptions.
def subscription_kinds=(kinds)
if new_record?
@_required_kinds = kinds
return
end
Subscription.transaction do
self.subscriptions = subscriptions.select { |s| kinds.include?(s.kind.to_s) }
subscriptions.update_all :revocation => nil
subscriptions.update_all({:confirmation => Time.zone.now}, :confirmation => nil)
kinds_left = subscriptions.map { |s| s.kind.to_s }
(kinds - kinds_left).each do |k|
s = subscriptions.create! :email => email, :kind => k.to_sym
s.activate!
end
end
end
def self.authenticate(email, pass)
customer = find_by_email(email)
if customer
expected_hashed_pwd = generate_encrypted_password(customer.salt, pass)
customer = nil unless expected_hashed_pwd == customer.hashed_password
end
customer
end
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
customer = Customer.where(:provider => auth.provider, :uid => auth.uid).first
if customer
return customer
else
registered_customer = Customer.where(:email => auth.info.email).first
if registered_customer
return registered_customer
else
customer = Customer.create(name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20],
)
end
end
end
private
def check_sub_related_changes
@email_changed = email_changed?
true
end
def encrypt_password
self.salt = object_id.to_s + rand.to_s
self.hashed_password = self.class.generate_encrypted_password(salt, password)
end
def ensure_geolocation
return true if geolocated?
base = [address1, address2, zip_code, city, 'France'].reject(&:blank?).map(&:strip).join(' ')
return true if base.blank?
geocoding = Geokit::Geocoders::MultiGeocoder.geocode(base)
auto_geocoded = geocoding.success? && geocoding.accuracy >= 4 # Town level
self.lat, self.lng = geocoding.lat, geocoding.lng if auto_geocoded
true
end
def self.generate_encrypted_password(salt, pass)
Digest::SHA1.hexdigest(salt.to_s + SALT.gsub(/\W/, '').downcase + pass.to_s)
end
def self.random_pronouncable_password(size = 4)
c = %w(b c d f g h j k l m n p qu r s t v w x z ch cr fr nd ng nk nt ph pr rd sh sl sp st th tr)
v = %w(a e i o u y)
(1..size * 2).inject('') { |acc, n| acc << (0 == n % 2 ? c[rand * c.size] : v[rand * v.size]) }
end
def setup_modifications
encrypt_password if password.present?
# self.password = nil # DEV NOTE: we need to keep it in memory for forgotten-password e-mail notifications
# Subscription.find_all_by_email(self.email).each { |s| s.customer = self }
end
def sync_subs
Subscription.update_all({ :customer_id => id }, :email => email)
self.subscription_kinds = @_required_kinds unless @_required_kinds.blank?
end
def sync_sub_related_changes
changes = {}
changes[:email] = email if @email_changed
subscriptions.update_all(changes) unless changes.empty?
end
def validate
if hashed_password.blank?
errors.add(:password, :blank)
end
if !email.blank? && !email_confirmation.blank? && email != email_confirmation
errors.add(:email, :confirmation)
end
errors.add(:terms_of_use, :accepted) unless terms_of_use
end
end
控制器/客户/ omniauth_callbacks_controller.rb
class Customers::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
@customer = Customer.find_for_facebook_oauth(request.env["omniauth.auth"], current_customer)
if @customer.persisted?
sign_in_and_redirect @customer, :event => :authentication #this will throw if @customer is not activated
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_customer_registration_url
end
end
end
答案 0 :(得分:1)
OmniAuth通过Facebook登录时,网址中没有app_id
参数。
您是否正确配置了应用? 你的Devise初始化程序中应该有一个关于OmniAuth的特定行,如:
config.omniauth :facebook, "APP_ID", "APP_SECRET"
APP_ID
和APP_SECRET
位于您创建的Facebook应用的详细信息页面中。再一次,将它们保密。您不应将它们直接放在代码中,而应使用Figaro gem和环境变量。
有关使用Devise实施OmniAuth Facebook的详细信息,请访问:https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview
<强>更新强>
事实上这已经完成了,但是你确认这些环境变量确实设置为正确的值吗?
我看到你在localhost上运行你的服务器,假设一个开发环境;你有没有将这些环境变量添加到你的环境中?