2016-01-08 45 views
8

我想在Rails 4中創建一個應用程序。我一直在嘗試過去3年(除了10天),以獲得設計工作。Rails 4 - 設計Omniauth(多策略)

我想按照這個教程:http://sourcey.com/rails-4-omniauth-using-devise-with-twitter-facebook-and-linkedin/

請不要推薦其他教程/寶石文檔。我已經嘗試了至少30個其他教程,並且該寶石文檔充滿了我不明白的錯誤和組件。

我目前的問題是,當我到達本教程的完成註冊步驟時,表單會詢問我的電子郵件地址。

的用戶控制器具有完成註冊方法:在這一行

undefined method `match' for {:host=>"localhost", :port=>3000}:Hash 

錯誤點:

 <div class="intpol3"><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></div> 

def finish_signup 
    # authorize! :update, @user 
    if request.patch? && params[:user] #&& params[:user][:email] 
     if @user.update(user_params) 
     @user.skip_reconfirmation! 
     # sign_in(@user, :bypass => true) 
     # redirect_to root_path, notice: 'Your profile was successfully updated.' 
     # redirect_to [@user, @user.profile || @user.build_profile] 
     sign_in_and_redirect(@user, :bypass => true) 
     else 
     @show_errors = true 
     end 
    end 
    end 

當我嘗試這一點,我得到這個錯誤

我的開發環境設置爲包含我的電子郵件發件人的所有配置詳細信息。

當我嘗試在生產模式相同的步驟,我得到這個錯誤:

after_create :gen_profile 

    def gen_profile 
    Profile.create(user: self) # Associations must be defined correctly for this syntax, avoids using ID's directly. 
    # Profile.save 
    end 

ActionView::Template::Error (No route matches {:action=>"show", :controller=>"profiles", :id=>nil} missing required keys: [:id]): 

它尋找一個配置文件ID,因爲我在我的用戶模型有一個after_create行動

本教程中的其他問題是身份表中的字段未被填充。

我很想找到已成功實施本教程的人員或者可以看到如何完成此項工作。

我的代碼是:

的Gemfile

gem 'devise', '3.4.1' 
gem 'devise_zxcvbn' 
gem 'omniauth' 
gem 'omniauth-oauth2', '1.3.1' 
gem 'omniauth-google-oauth2' 
gem 'omniauth-facebook' 
gem 'omniauth-twitter' 
gem 'omniauth-linkedin-oauth2' 
gem 'google-api-client', require: 'google/api_client' 

路線

devise_for :users, #class_name: 'FormUser', 
      :controllers => { 
       :registrations => "users/registrations", 
       # :omniauth_callbacks => "users/authentications" 
       :omniauth_callbacks => 'users/omniauth_callbacks' 
      } 

    # get '/auth/:provider/callback' => 'users/authentications#create' 
    # get '/authentications/sign_out', :to => 'users/authentications#destroy' 

    # PER SOURCEY TUTORIAL ---------- 
    match '/users/:id/finish_signup' => 'users#finish_signup', via: [:get, :patch], :as => :finish_signup 

resources :users do 
    resources :profiles, only: [:new, :create] 
    end 

user.rb

類用戶<的ActiveRecord :: Base的

TEMP_EMAIL_PREFIX = '[email protected]' 
    TEMP_EMAIL_REGEX = /\[email protected]/ 

    devise :database_authenticatable, :registerable, 
     :recoverable, :rememberable, :trackable, 
      :confirmable, :lockable, 
     # :zxcvbnable, 
     :omniauthable, :omniauth_providers => [:facebook, :linkedin, :twitter, :google_oauth2 ] 





    # --------------- associations 

    has_many :authentications, :dependent => :delete_all 

    has_one :profile 

    has_many :identities 


    # --------------- scopes 

    # --------------- validations 

    # validates_presence_of :first_name, :last_name 
    validates_uniqueness_of :email 

    # per sourcey tutorial - how do i confirm email registrations are unique? 
    # this is generating an error about the options in the without function -- cant figure out the solution 
    validates_format_of :email, :without => TEMP_EMAIL_REGEX, on: :update 


    # --------------- class methods 


# sourcey tutorial 

def self.find_for_oauth(auth, signed_in_resource = nil) 
    # Get the identity and user if they exist 
    identity = Identity.find_for_oauth(auth) 

    # If a signed_in_resource is provided it always overrides the existing user 
    # to prevent the identity being locked with accidentally created accounts. 
    # Note that this may leave zombie accounts (with no associated identity) which 
    # can be cleaned up at a later date. 
    user = signed_in_resource ? signed_in_resource : identity.user 

    # p '11111' 

    # Create the user if needed 
    if user.nil? 
     # p 22222 
     # Get the existing user by email if the provider gives us a verified email. 
     # If no verified email was provided we assign a temporary email and ask the 
     # user to verify it on the next step via UsersController.finish_signup 
     email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email) 
     email = auth.info.email if email_is_verified # take out this if stmt for chin yi's solution 
     user = User.where(:email => email).first if email 

     # Create the user if it's a new registration 
     if user.nil? 
     # p 33333 
     user = User.new(
      # at least one problem with this is that each provider uses different terms to desribe first name/last name/email. See notes on linkedin above 
      first_name: auth.info.first_name, 
      last_name: auth.info.last_name, 
      email: email ? email : "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com", 
      #username: auth.info.nickname || auth.uid, 
      password: Devise.friendly_token[0,20]) 
# fallback for name fields - add nickname to user table 
     # debugger 

     # if email_is_verified 
      user.skip_confirmation! 
     # end 
     # user.skip_confirmation! 

     user.save! 
     end 
    end 

    # Associate the identity with the user if needed 
    if identity.user != user 
     identity.user = user 
     identity.save! 
    end 
    user 
    end 

    def email_verified? 
    self.email && TEMP_EMAIL_REGEX !~ self.email 
    end 

用戶控制器

class UsersController < ApplicationController 

before_action :set_user, only: [:index, :show, :edit, :update, :finish_signup, :destroy] 

# i added finish_signup to the set_user action (not shown in tutorial) 

    def index 
    # if params[:approved] == "false" 
    # @users = User.find_all_by_approved(false) 
    # else 
     @users = User.all 
    # end 

    end 

    # GET /users/:id.:format 
    def show 
    # authorize! :read, @user 
    end 

    # GET /users/:id/edit 
    def edit 
    # authorize! :update, @user 
    end 

    # PATCH/PUT /users/:id.:format 
    def update 
    # authorize! :update, @user 
    respond_to do |format| 
     if @user.update(user_params) 
     sign_in(@user == current_user ? @user : current_user, :bypass => true) 
     format.html { redirect_to @user, notice: 'Your profile was successfully updated.' } 
     format.json { head :no_content } 
     else 
     format.html { render action: 'edit' } 
     format.json { render json: @user.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # GET/PATCH /users/:id/finish_signup 
    def finish_signup 
    # authorize! :update, @user 
    if request.patch? && params[:user] #&& params[:user][:email] 
     if @user.update(user_params) 
     @user.skip_reconfirmation! 
     # sign_in(@user, :bypass => true) 
     # redirect_to root_path, notice: 'Your profile was successfully updated.' 
     # redirect_to [@user, @user.profile || @user.build_profile] 
     sign_in_and_redirect(@user, :bypass => true) 
     else 
     @show_errors = true 
     end 
    end 
    end 

    # DELETE /users/:id.:format 
    def destroy 
    # authorize! :delete, @user 
    @user.destroy 
    respond_to do |format| 
     format.html { redirect_to root_url } 
     format.json { head :no_content } 
    end 
    end 

    private 
    def set_user 
     @user = User.find(params[:id]) 
    end 

    def user_params 
     # params.require(:user).permit(policy(@user).permitted_attributes) 
     accessible = [ :first_name, :last_name, :email, :avatar ] # extend with your own params 
     accessible << [ :password, :password_confirmation ] unless params[:user][:password].blank? 
     # accessible << [:approved] if user.admin 
     params.require(:user).permit(accessible) 
    end 

end 

omniauth回調控制器

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController 

    def self.provides_callback_for(provider) 
    class_eval %Q{ 
     def #{provider} 
     @user = User.find_for_oauth(env["omniauth.auth"], current_user) 

     if @user.persisted? 
      sign_in_and_redirect @user, event: :authentication 

      set_flash_message(:notice, :success, kind: "#{provider}".capitalize) if is_navigational_format? 
     else 
      session["devise.#{provider}_data"] = env["omniauth.auth"] 
      redirect_to new_user_registration_url 
     end 
     end 
    } 
    end 

    # , current_user has been deleted from the end of line 51 
    #come back to put current_user into fidn by oauth so i can link other accounts - i have added this back for the purpose of solving the current problem 

      # puts current_user.inspect 
      # sign_in_and_redirect [@user, @user.profile || @user.build_profile] 

      # sign_in_and_redirect_user(:user, event: :authentication) 


    [:twitter, :facebook, :linkedin, :google_oauth2].each do |provider| 
    provides_callback_for provider 
    end 

    def after_sign_in_path_for(resource) 
    if resource.email_verified? 
     super resource 
    else 
     finish_signup_path(resource) 
    end 
    end 

end 

註冊控制器

class Users::RegistrationsController < Devise::RegistrationsController 




     protected 

     def after_sign_up_path_for(resource) 
     profile_path(resource) 
    end 


    private 
    def user_params 
      params.require(:user).permit(:first_name, :last_name, :email, :password) 
    end 

    end 

身份。RB

class Identity < ActiveRecord::Base 


    belongs_to :user 
    validates_presence_of :uid, :provider 
    validates_uniqueness_of :uid, :scope => :provider 



    def self.find_for_oauth(auth) 
    find_or_create_by(uid: auth.uid, provider: auth.provider) 
    end 


end 

身份控制器

class IdentitiesController < ApplicationController 
    before_action :set_identity, only: [:show, :edit, :update, :destroy] 
    before_action :authenticate_user! 

    # GET /identities 
    # GET /identities.json 
    def index 
    @identities = Identity.all 
    end 

    # GET /identities/1 
    # GET /identities/1.json 
    def show 
    end 

    # GET /identities/new 
    def new 
    @identity = Identity.new 
    end 

    # GET /identities/1/edit 
    def edit 
    end 

    # POST /identities 
    # POST /identities.json 
    def create 
    @identity = Identity.new(identity_params) 

    respond_to do |format| 
     if @identity.save 
     format.html { redirect_to @identity, notice: 'Identity was successfully created.' } 
     format.json { render :show, status: :created, location: @identity } 
     else 
     format.html { render :new } 
     format.json { render json: @identity.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # PATCH/PUT /identities/1 
    # PATCH/PUT /identities/1.json 
    def update 
    respond_to do |format| 
     if @identity.update(identity_params) 
     format.html { redirect_to @identity, notice: 'Identity was successfully updated.' } 
     format.json { render :show, status: :ok, location: @identity } 
     else 
     format.html { render :edit } 
     format.json { render json: @identity.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # DELETE /identities/1 
    # DELETE /identities/1.json 
    def destroy 
    @identity.destroy 
    respond_to do |format| 
     format.html { redirect_to identities_url, notice: 'Identity was successfully destroyed.' } 
     format.json { head :no_content } 
    end 
    end 

    private 
    # Use callbacks to share common setup or constraints between actions. 
    def set_identity 
     @identity = Identity.find(params[:id]) 
    end 

    # Never trust parameters from the scary internet, only allow the white list through. 
    def identity_params 
     params[:identity] 
    end 
end 

色器件郵包 - 電流問題的確認

 <div class="intpol3"><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></div> 

內容:

  1. 在開發模式:有一個與一個問題鏈接到confi信息令牌。我找不到任何可能會出現這種情況的材料。該錯誤是:(::的ActionView模板::錯誤(未定義的方法`匹配」爲{:主機=> 「本地主機」,:端口=> 3000}:散列):

  2. 在生產模式中,存在一個錯誤消息是:ActionView :: Template :: Error(沒有路由匹配{:action =>「show」,:controller =>「profiles」,:id => nil}缺少必需的密鑰:[:ID]):

我的簡檔航線:

resources :profiles, only: [:show, :edit, :update, :destroy] 
resources :users do 
    resources :profiles, only: [:new, :create] 
    end 
  • 無在字段身份模型正在填充。他們都顯示爲零。
  • 不同的事情做得比如圖教程:

    1. 我也讓電子郵件註冊

    2. 我的用戶控制器動作之前加上「finish_sign_up」到set_user

    3. 我加了g +策略(這意味着我的寶石略有不同)

    4. 我的新用戶方法不使用原始信息。它使用oauth處理的信息。

    5. 我在完成註冊方法中的重定向略有不同,儘管我已經評論過並回到了教程中設置的方式以嘗試使其工作(儘管上述問題正在重複)。

    我要瘋了試圖解決這些問題。我會說3年太長了,不能堅持這個問題。如果任何人都可以提供幫助,我會先付10倍,然後再付一些。謝謝。

    +0

    我已經成功完成了這項工作。你可以從導軌控制檯驗證你的配置文件實際上是在創建嗎?你有更具體的問題嗎? – errata

    +0

    是 - 爲用戶創建配置文件。我的具體問題是如何獲得本教程設置?目前的錯誤是直接的挑戰,所以如果有辦法解決任何可能導致這個問題的方法,我想首先解決這個問題。 – Mel

    +0

    您好,勘誤表 - 您是否在代碼中添加某種按鈕以允許用戶(一次在會話中)添加其他用戶身份?你在哪裏做的?我在想,當所有當前問題得到解決時,將其添加到完成註冊方法可能是有意義的。你是怎麼處理的? – Mel

    回答

    1
    <div class="intpol3"><%= link_to 'Confirm my account', 
        confirmation_url(@resource, confirmation_token: @token) %></div> 
    

    嘗試resource而不是@resource。 AFAIK它只是一個helper_method,而不是一個實例變量。

    我認爲這將在生產中完全解決您的問題。由於@resourceresource不同,它尚未設置,並且您基本上呼叫confirmation_url(nil, confirmation_token: @token),並且nil正在傳遞給錯誤消息。

    在開發過程中,似乎還有一個額外的問題,最有可能與您如何在config/environments/development.rb中配置config.action_mailer.default_url_options以及最有可能在ActionDispatch::Http::Url.build_host_url中引發異常有關。我懷疑你有這樣的:

    config.action_mailer.default_url_options[:host] = { host: 'localhost', port: 9000 } 
    

    修改成:

    config.action_mailer.default_url_options[:host] = 'localhost:9000' 
    

    ,看看是否能解決一切問題。如果我對如何配置config.action_mailer.default_url_options錯誤,請粘貼您的config/environments/development.rb和您的開發錯誤的完整堆棧跟蹤,以便我們可以進一步幫助您。