2013-02-27 1 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. В этом случае, что я должен сделать, чтобы вернуть его в мои сообщения # create?

Обновление: Я получил это предупреждение о том, цепь фильтра прерывается в тот момент, я имею в другой метод

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 вы создали несколько вспомогательных методы:

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, воссоздать объект, установить его статус в общедоступный и связать его с current_user.

+0

Большое спасибо за очень подробный ответ. Не могли бы вы объяснить, что происходит в Posts # create, если пользователь не заходит? Должен ли я вызвать require_login в этом методе? – AdamNYC