You're approaching this wrongly. You're handling login and the check wether someone is logged in in the same step.
Consider using a sessions_controller to handle all your signup/login/logout logic, for example:
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'
Then, in your ApplicationController you set up a couple of helper methods:
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
These helper methods are available in all your controllers since they all inherit from ApplicationController. You could then tell your PostsController to send users who are not logged in to go and log in and after doing that they get returned to the PostsController.
Then to address your requirement of saving a post only after authentication: Either you do create the post, save it, but only update it to being public after the user is authenticated, or you store the contents of the post in the session and restore them after the user is authenticated:
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
Note that this is a rather vulnerable approach. I would rather suggest to actually create the Post, mark it as not yet public and store only the post's id in the Session. After authentication you could then find that post_id, recreate the object from, set its status to public and associate it with the current_user.