Hartl 教程 + Omniauth:登录而不是登录

Hartl Tutorial + Omniauth: Log In not Logging In

我尝试将 omniauth 与 Hartl 教程用户注册身份验证集成。我考虑过将 hartl 教程身份验证切换到 Devise,然后将 Devise 切换到 omniauth(因为他们是 Railscast 的一集),但我担心从 Hartl 切换到 Devise 将是选项中最困难的集成。你怎么看?

目前,如果我去 http://0.0.0.0:3000/authentications,我将被带到 facebook 的登录页面。单击 link 后,我将登录到 facebook。分数!但随后我被重定向到根路由:

http://0.0.0.0:3000/#=

where page shows me "Welcome to the Sample App: Sign up now!" 好像我没有登录。我对整个过程感到困惑,所以如果你能告诉我哪里出错了,我将不胜感激。

class AuthenticationsController < ApplicationController

  def index
    @authentications = current_user.authentications if current_user
  end
    
def create
  omniauth = request.env["omniauth.auth"]
  authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
  if authentication
    flash[:notice] = "Signed in successfully."
    sign_in_and_redirect(:user, authentication.user)
  elsif current_user
    current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
    flash[:notice] = "Authentication successful."
    redirect_to authentications_url
  else
    user = User.new
    user.apply_omniauth(omniauth)
    if user.save
      flash[:notice] = "Signed in successfully."
      sign_in_and_redirect(:user, user)
    else
      session[:omniauth] = omniauth.except('extra')
      redirect_to root_url
    end
  end
end
    
  def destroy_facebook
    @authentication = current_user.authentications.find(params[:id])
    @authentication.destroy_facebook
    flash[:notice] = "Successfully destroyed authentication."
    redirect_to authentications_url
  end

protected

# This is necessary since Rails 3.0.4
# See https://github.com/intridea/omniauth/issues/185
# and http://www.arailsdemo.com/posts/44
def handle_unverified_request
  true
end
end

<% if @authentications %>
 <% unless @authentications.empty? %>
  <p><strong>You can sign in to this account using:</strong></p>
   <div class="authentications">
    <% for authentication in @authentications %>
     <div class="authentication">
      <%= image_tag "#{authentication.provider}_32.png",
      :size => "32x32" %>
      <div class="provider"><%= authentication.provider.titleize↵   
      %></div>
      <div class="uid"><%= authentication.uid %></div>
       <%= link_to "X", authentication, :confirm =>
      'Are you sure you want to remove this authentication 
      option?', :method => :delete, :class => "remove" %>
     </div>
     <% end %>
     <div class="clear"></div>
    </div>
   <% end %>
   <p><strong>Add another service to sign in with:</strong></p>
  <% else %>
  <p><strong>Sign in through one of these services:</strong></p>
<% end %>

<a href="/auth/facebook" class="auth_provider">
  <%= image_tag "facebook_64.png", :size => "64x64",
  :alt => "Facebook" %>Facebook</a>
<div class="clear"></div>

class User < ActiveRecord::Base
  has_many :authentications
  has_many :habits, dependent: :destroy
  has_many :levels
  has_many :valuations, dependent: :destroy
  has_many :goals, dependent: :destroy
  has_many :quantifieds, dependent: :destroy
  has_many :results, dependent: :destroy
  accepts_nested_attributes_for :quantifieds, :reject_if => :all_blank, :allow_destroy => true
  accepts_nested_attributes_for :results, :reject_if => :all_blank, :allow_destroy => true
  has_many :active_relationships, class_name:  "Relationship",
                                  foreign_key: "follower_id",
                                  dependent:   :destroy
  has_many :passive_relationships, class_name:  "Relationship",
                                   foreign_key: "followed_id",
                                   dependent:   :destroy
  has_many :following, through: :active_relationships,  source: :followed
  has_many :followers, through: :passive_relationships, source: :follower
  attr_accessor :remember_token, :activation_token, :reset_token
  before_save   :downcase_email
  before_create :create_activation_digest
  validates :name,  presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  has_secure_password
  validates :password, length: { minimum: 6 }
  validates :password, length: { minimum: 6 }, allow_blank: true

def apply_omniauth(omniauth)
  authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'])
end

def password_required?
  (authentications.empty? || !password.blank?) && super
end

  # Returns the hash digest of the given string.
  def User.digest(string)
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                  BCrypt::Engine.cost
    BCrypt::Password.create(string, cost: cost)
  end

  # Returns a random token.
  def User.new_token
    SecureRandom.urlsafe_base64
  end

  # Remembers a user in the database for use in persistent sessions.
  def remember
    self.remember_token = User.new_token
    update_attribute(:remember_digest, User.digest(remember_token))
  end

  # Forgets a user. NOT SURE IF I REMOVE
  def forget
    update_attribute(:remember_digest, nil)
  end

  # Returns true if the given token matches the digest.
  def authenticated?(attribute, token)
    digest = send("#{attribute}_digest")
    return false if digest.nil?
    BCrypt::Password.new(digest).is_password?(token)
  end

  # Activates an account.
  def activate
    update_attribute(:activated,    true)
    update_attribute(:activated_at, Time.zone.now)
  end

  # Sends activation email.
  def send_activation_email
    UserMailer.account_activation(self).deliver_now
  end

  def create_reset_digest
    self.reset_token = User.new_token
    update_attribute(:reset_digest,  User.digest(reset_token))
    update_attribute(:reset_sent_at, Time.zone.now)
  end

  # Sends password reset email.
  def send_password_reset_email
    UserMailer.password_reset(self).deliver_now
  end

   # Returns true if a password reset has expired.
  def password_reset_expired?
    reset_sent_at < 2.hours.ago
  end

  # Returns a user's status feed.
  def feed
    following_ids = "SELECT followed_id FROM relationships
                     WHERE  follower_id = :user_id"
    Habit.where("user_id IN (#{following_ids})
                     OR user_id = :user_id", user_id: id)
    Valuation.where("user_id IN (#{following_ids})
                     OR user_id = :user_id", user_id: id)
    Goal.where("user_id IN (#{following_ids})
                     OR user_id = :user_id", user_id: id)
    Quantified.where("user_id IN (#{following_ids})
                     OR user_id = :user_id", user_id: id)
  end

  # Follows a user.
  def follow(other_user)
    active_relationships.create(followed_id: other_user.id)
  end

  # Unfollows a user.
  def unfollow(other_user)
    active_relationships.find_by(followed_id: other_user.id).destroy
  end

  # Returns true if the current user is following the other user.
  def following?(other_user)
    following.include?(other_user)
  end

  private

    # Converts email to all lower-case.
    def downcase_email
      self.email = email.downcase
    end

    # Creates and assigns the activation token and digest.
    def create_activation_digest
      self.activation_token  = User.new_token
      self.activation_digest = User.digest(activation_token)
    end
end

class RegistrationsController < Devise::RegistrationsController
  def create
    super
    session[:omniauth] = nil unless @user.new_record?
  end
  
  private
  
  def build_resource(*args)
    super
    if session[:omniauth]
      @user.apply_omniauth(session[:omniauth])
      @user.valid?
    end
  end
end

class Authentication < ActiveRecord::Base
  belongs_to :user

 def provider_name
   if provider == 'open_id'
     "OpenID"
   else
     provider.titleize
   end
 end
end

Rails.application.routes.draw do
  get 'auth/:provider/callback', to: 'authentications#create'
  get 'auth/failure', to: redirect('/')
  get 'signout', to: 'authentications#destroy_facebook', as: 'signout'

  get 'password_resets/new'

  get 'password_resets/edit'

  resources :authentications

  resources :habits

  resources :goals

  resources :valuations

  resources :quantifieds
  
  resources :results

  resources :users, controller: 'registrations'

  resources :account_activations, only: [:edit]

  resources :password_resets,     only: [:new, :create, :edit, :update]

  resources :relationships,       only: [:create, :destroy]

  get 'tags/:tag', to: 'valuations#index', as: :tagvaluations
  get 'tags/:tag', to: 'habits#index', as: :taghabits
  get 'tags/:tag', to: 'goals#index', as: :taggoals
  get 'tags/:tag', to: 'quantifieds#index', as: :tagquantifieds

  resources :users do
    member do
      get :following, :followers
    end
  end

  get    'about'   => 'pages#about'
  get    'signup'  => 'users#new'
  get    'login'   => 'sessions#new'
  post   'login'   => 'sessions#create'
  delete 'logout'  => 'sessions#destroy'

  root 'pages#home'
  # The priority is based upon order of creation: first created -> highest priority.
  # See how all your routes lay out with "rake routes".

  # You can have the root of your site routed with "root"
  # root 'welcome#index'

  # Example of regular route:
  #   get 'products/:id' => 'catalog#view'

  # Example of named route that can be invoked with purchase_url(id: product.id)
  #   get 'products/:id/purchase' => 'catalog#purchase', as: :purchase

  # Example resource route (maps HTTP verbs to controller actions automatically):
  #   resources :products

  # Example resource route with options:
  #   resources :products do
  #     member do
  #       get 'short'
  #       post 'toggle'
  #     end
  #
  #     collection do
  #       get 'sold'
  #     end
  #   end

  # Example resource route with sub-resources:
  #   resources :products do
  #     resources :comments, :sales
  #     resource :seller
  #   end

  # Example resource route with more complex sub-resources:
  #   resources :products do
  #     resources :comments
  #     resources :sales do
  #       get 'recent', on: :collection
  #     end
  #   end

  # Example resource route with concerns:
  #   concern :toggleable do
  #     post 'toggle'
  #   end
  #   resources :posts, concerns: :toggleable
  #   resources :photos, concerns: :toggleable

  # Example resource route within a namespace:
  #   namespace :admin do
  #     # Directs /admin/products/* to Admin::ProductsController
  #     # (app/controllers/admin/products_controller.rb)
  #     resources :products
  #   end
end

class CreateAuthentications < ActiveRecord::Migration
  def change
    create_table :authentications do |t|
      t.integer :user_id
      t.string :provider
      t.string :uid
      t.string :index
      t.string :create
      t.string :destroy_facebook

      t.timestamps null: false
    end
  end
end

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string   :name
      t.string   :email
     t.text     :missed_days
     t.text     :missed_levels

      t.timestamps null: false
    end
  end
end

是的,我只是在你身上倾倒了很多。我没有方向。我关注了 Railscasts 的 omniauth:http://railscasts.com/episodes/235-omniauth-part-1?view=asciicast, http://railscasts.com/episodes/236-omniauth-part-2?view=asciicast

同样的错误曾经让我很头疼。检查您用于 facebook 的电子邮件是否已在您的数据库中。如果它在那里然后删除它并且它应该工作。