2013-02-27 32 views
2

我有一個控制器PostsController,它允許用戶在登錄之前創建帖子。但要保存它,用戶必須使用Omniauth登錄。before_filter從另一個控制器的方法

在PostsController,我有:

class PostsController < ApplicationController 
    before_filter :authenticate_user_by_service, :only => :create 
    def create 
    ... 
    end 

private 
    def authenticate_user_by_service 
    redirect_to user_omniauth_authorize_path(:facebook) 
    end 

現在,我還有一個控制器來從Facebook,這就是所謂ServicesController

處理回調
class ServicesController < ApplicationController 
    def create 
    auth = request.env["omniauth.auth"] 
    ... authentication logic here ... 
    sign_in(:user, service.user) 
    end 
    method_alias: :facebook, :create 

通常情況下,進行身份驗證,之後,籤我將重定向到:返回。

但是,這裏使用services#create作爲before_filter。在這種情況下,我應該怎麼做才能讓它回到我的帖子#創建?

更新:我得到這個警告稱該過濾器鏈就在我指的是一個不同的方法

Started POST "/posts" for 127.0.0.1 at 2013-02-26 23:47:41 -0500 
Processing by PostsController#create as HTML 
    Parameters: {"utf8"=>"✓", "authenticity_token"=>"H0as8=", "post"=>{"post"=>"bla bla"}, "commit"=>"Create Post"} 
Redirected to http://localhost:3000/users/auth/facebook 
Filter chain halted as :authenticate_user_by_service rendered or redirected 

回答

1

你錯誤地處理這個時刻被中斷。您正在處理登錄,並在同一步驟中檢查某人是否已登錄。

考慮使用sessions_controller來處理所有的註冊/登錄/註銷邏輯,例如:

class SessionsController < ApplicationController 
    def new # this will be /login 
    session[:return_to] = params[:returnto] unless params[:returnto].nil? 
    redirect_to "/auth/facebook" 
    end 

    def create # this will be the callback after the user is authenticated 
    auth_token = request.env["omniauth.auth"]["credentials"]["token"] 
    # you'll need to write this based on your app's requirement. 
    # Find a user or create one if he doesn't exist yet. 
    user = User.find_or_create_authenticated_user(auth_token) 

    if user.present? 
     session[:user_id] = user.id # this stores the current user's id in your session and lets Rails remember him for you. 
     redirect_to return_or(products_url) # see below for the usage of return_or 
     return 
    end 

    redirect_to root_url, alert: 'User not found or invalid' 
    end 

    def destroy # /logout 
    session[:user_id] = nil 
    redirect_to root_url 
    end 
end 


#routes.rb 
match '/logout' => 'sessions#destroy', :as => :logout 
match '/login' => 'sessions#new', :as => :login 
match '/auth/facebook/callback' => 'sessions#create' 

然後,在你ApplicationController您設置的helper方法:

class ApplicationController < ActionController::Base 

    protected 
    # Use this in your views and controllers to get 
    # a handle of the user that is currently logged in. 
    # it will return nil if there is no user logged in. 
    def current_user 
    @current_user ||= User.find(session[:user_id]) if session[:user_id] 
    end 
    helper_method :current_user 

    # Use this to check wether a user is logged in. 
    # returns true if there is a user, false otherwise. 
    def logged_in? 
    !current_user.nil? 
    end 
    helper_method :logged_in? 

    # Block access to controllers or actions based on 
    # wether there's a user or not. 
    def require_login 
    unless logged_in? 
     # if we need the user to log in, we send him on his way 
     # but send him back to the current page afterwards. 
     session[:return_to] = request.fullpath 
     redirect_to root_url(subdomain: false), :alert => "Please login" 
    end 
    end 

    # When a user is not logged in, but you send him to log in, 
    # you can force him to return to the url he was in or if nothing 
    # was set go to a standard path. 
    # See this being set up in SessionsController#new and in require_login and then 
    # being used in SessionsController#create 
    def return_or(path) 
    session.delete(:return_to) || path 
    end 
    helper_method :return_or 
end 

這些輔助方法在所有控制器中都可用,因爲它們都從ApplicationController繼承。然後,您可以告訴您的PostsController發送未登錄的用戶去登錄,並在完成後返回到PostsController。

然後爲了滿足您在驗證後才保存帖子的需求:您可以創建帖子並保存,但只需在用戶通過身份驗證後將其更新爲公開狀態,或者將帖子的內容存儲在會話並在用戶通過身份驗證後恢復它們:

class PostsController < ApplicationController 
    def new 
    @post = Post.new(session[:post_params] || {}) 
    end 

    def create 
    if logged_in? 
     @post = Post.create(params[:post]) 
     # ... etc 
    else 
     session[:post_params] = params[:post] 
     session[:return_to] = new_post_path 
    end 
    end 
end 

請注意,這是一個相當易受攻擊的方法。我寧願建議實際創建Post,將其標記爲尚未公開,並在會話中僅存儲帖子的id。驗證後,您可以找到post_id,重新創建對象,將其狀態設置爲public,並將其與current_user關聯。

+0

非常感謝您的詳細解答。你能否解釋一下在帖子中發生了什麼#如果用戶沒有登錄,請創建?我應該在這個方法中調用require_login嗎? – AdamNYC 2013-02-27 15:41:02

相關問題