I've got a Rails 3.2.8 app using Sorcery for authentication. Sorcery provides a current_user method, pretty standard stuff.
My app has subscriptions, they work pretty much in the standard resourceful way. Here's the abridged version of the controller:
class SubscriptionsController < ApplicationController
before_filter :require_login
force_ssl
def show
#subscription = SubscriptionPresenter.new( current_user )
end
def create
handler = StripeHandler.new( current_user )
...
end
def destroy
handler = StripeHandler.new( current_user )
...
end
end
The #show action works fine, current_user loads. However, right now #create does not work, because current_user ends up being nil in that action.
So, why is current_user nil when a logged in user posts to this action? My guess is something about the way sessions work over SSL, but I don't know what I'm missing here...
I figured this out. It turns out that I was actually getting a silent exception in a 3rd-party library that I was interacting with, and that exception was causing an 'unauthorized' request which logged the user out. After patching that it turns out there was nothing wrong with my controller specifically. Thanks for the pointers, all.
Related
I'm wondering what would be the best way to handle the following:
I have an authentication method (used as a before_action) as follows that checks if a user_id is in the session when the login page is requested. If the user_id is detected, then it redirects the user to dashboard path.
def already_validated
if session[:uid] == user.id
redirect_to dash_path
end
end
This is leading to a too many redirect errors which I understand. I can see in pry that it's just evaluating that before_action filter every-time the page loads. That's what leads to too many redirects.
My question is what is the best way to handle this type of setup. Is there a way in rails to only evaluate on the first redirect? I thought of using a temp flag to tell if the redirect happened before. That doesn't seem very elegant though. I'm sure there is an easier/better way to manage it.
Thanks for any advice you can provide.
There has to be an exception on your before_action: you don't want to call it on the dash_path. If a user enters there and is validated, it should stay there (as what the redirect would do) and if it is not validated it should just stay there (as with any other url that fails this validation process).
There is no point on checking if it is validated as the result will always be to stay on the same page.
Then in your controller you have to specify that you want an exception on the before_action:
class SomeController < ApplicationController
before_action: :already_validated, except: [:dash_action]
def is_validated_action # the method that causes the redirect
end
def dash_action # action of dash_path url
end
def already_validated
if session[:uid] == user.id
redirect_to dash_path
end
end
end
If you want some validation before the hypothetical dash_action then create a new method for it. Be sure that you don't have circular references or it will be pretty difficult to debug on the long run.
You can just tell Rails to skip the before filter in the controller that handles the dash_path:
# in the controller
skip_before_action :already_validated
Read about Filters in the Rails Guides.
I've found a seemingly solution to my problem but I keep on getting an internal server error.
def after_sign_in_path_for(resource)
current_user_path
end
I currently have a user model and an admin model and I want both to go to the same web page. Is what the method after_sign_in_path_for takes in as a parameter supposed to be the model I want to use? I'm not sure what the (resource) is in this context...
I think def after_sign_in_path_for(resource) is already correct, the only problem is current_user_path, you can use as follow
def after_sign_in_path_for(resource)
user_path(current_user)
end
I'm using Devise to handle users in a shopping application. What I want to do is create a new cart each time a user signs in (and ideally, destroy the same cart each time a user signs out, but I'll just stick to that first part for this question).
So far, I've looked at this question: Devise call backs
And I came up with this:
class ApplicationController < ActionController::Base
helper :all
protect_from_forgery
before_filter :fetch_categories
.
.
.
Warden::Manager.after_authentication do
session[:cart_id] ||= Cart.create!.id
end
end
...But clearly this isn't correct, because I'm getting this error:
NameError in Devise::SessionsController#create
undefined local variable or method `session' for ApplicationController:Class
Is there some other way I can tell the application controller to respond to a user sign in, or should I be putting this code elsewhere (other than the application controller)? Thanks for any help.
Glancing at the docs, it looks like you can do something like this:
Warden::Manager.after_authentication do |user, auth, opts|
auth.session[:cart_id] ||= Cart.create!.id
end
Simpally write a before filter
In application controller
before_filter :set_current_user
def set_current_user
Authorization.current_user = current_user
end
and
you can check throughout application
using
` if !current_user.nil?
end`
I've been doing a ton of reading on the way that flash[]= works in rails and understand that when you redirect_to, to use the flash[...]=..., and if you are rendering the action after assignment, then flash.now[...]...; however, my application's flash is persisting indefinitely, never actually going away during the session.
This question is a hypothetical. If I have a controller,
class MyController < ApplicationController
def index
if my_cond
flash.now[:notice] = "Your condition is true"
else
flash[:notice] = "Your condition isn't true"
redirect_to some_other_rendering_action
end
end
end
If I redirect this time, then the next time I redirect, let's say via clicking a link that connects to some action that redirects to another render, but leaves flash unmodified, then it renders the flash. The problem is this happens indefinitely, doesn't even end after one redirect.
How would you suggest troubleshooting this issue? The application is probably 35k lines, and already has been washed to follow the flash and flash.now solution recommendations posted everywhere, so where do we look?
rails 2.3.5 high volume site, apache/mongrel
ADDING INFORMATION:
The flash is persisting in the session as well.
flash: !map:ActionController::Flash::FlashHash
:notice: You must be signed in to view this page.
I suggest looking for flash.keep calls and if you have no luck and want to get rid of the behavior, add an after_filter that calls flash.discard to your ApplicationController
class ApplicationController < ActionController::Base
after_filter :discard_flash
private
def discard_flash
flash.discard
end
end
I know this sounds like a really, really simple use case and I'm hoping that it is, but I swear I've looked all over the place and haven't found any mention of any way - not even the best way - of doing this.
I'm brand-spanking new to Ruby, Rails and everything surrounding either (which may explain a lot). The dummy app that I'm using as my learning tool requires authentication in order to do almost anything meaningful, so I chose to start by solving that problem. I've installed the AuthLogic gem and have it working nicely to the extent that is covered by the intro documentation and Railscast, but now that I can register, login and logout...I need to do something with it.
As an example, I need to create a page where users can upload images. I'm planning to have an ImagesController with an upload action method, but I want that only accessible to logged in users. I suppose that in every restricted action I could add code to redirect if there's no current_user, but that seems really verbose.
Is there a better way of doing this that allows me to define or identify restricted areas and handle the authentication check in one place?
Make sure you have these methods in your application_controller.rb
def current_user_session
return #current_user_session if defined?(#current_user_session)
#current_user_session = UserSession.find
end
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.record
end
def require_user
unless current_user
store_location
flash[:notice] = "You must be logged in to access this page"
redirect_to new_user_session_url
return false
end
end
Then in your controllers you can use a before filter to limit access to pages
class ExamplesController < ActionController::Base
before_filter :require_user, :only => :private
def public
// some public stuff
end
def private
// some protected stuff
end
end
before_filter is your friend here. You define a require_authentication function that returns false if there is no valid session and then set it up as a before_filter in the controllers and actions to your liking.
Take a look at the Authlogic Sample application, which defines some filters in the application_controller.rb and then uses it where needed (for example here, where you need to be logged to destroy your account, and not logged to create a new one.
You will need to use a before_filter on your page so that only logged in users can see it. If you want a running example of how Authlogic should be used (including the before_filter stuff), you can check out the Authlogic Exmaple from Github.
You have the entire code Gist available here at Github. Its roughly 360 lines of code. Inclusive of steps.
http://gist.github.com/96556.txt