I'm trying to build a "just click on your name to login" system using auth_logic. My user model has an email and name field. To login, I simply do:
UserSession.create(@user, true)
Unfortunately that doesn't result in a session being created. Using a debugger I found this message:
#<UserSession: {:unauthorized_record=>"<protected>"}>
My user model just has one line:
acts_as_authentic
User session line has this, which I found somewhere. I'm not sure what it does and I've tried with and without:
class UserSession < Authlogic::Session::Base
def to_key
new_record? ? nil : [ self.send(self.class.primary_key) ]
end
end
The database (I'm also not sure if that user_sessions table is needed):
create_table "sessions", :force => true do |t|
t.string "session_id", :null => false
t.text "data"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
create_table "user_sessions", :force => true do |t|
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", :force => true do |t|
t.datetime "created_at"
t.datetime "updated_at"
t.string "persistence_token"
t.string "email"
t.string "name"
end
I'm using Rails 3.0.9 and my Gemfile says (I tried both the normal and the Github authlogic gem):
gem 'rails', '3.0.9'
gem 'sqlite3'
gem "authlogic" #, :git => 'git://github.com/odorcicd/authlogic.git', :branch => 'rails3'
Here's the rest of the source code.
I had this problem a few days ago on a similar project and it "just went away" at some point. I just don't remember how.
Any ideas? This is driving me nuts...
Possible solution... it looks like there are two versions of those helper method examples floating around. There is the one that we used:
@current_user = current_user_session && current_user_session.user
and then there is the newer version that is in some newer tutorials and examples:
@current_user = current_user_session && current_user_session.record
Apparently, when .user (or whatever the login field is) is called on the session object, it returns the unauthorized_record, whereas .record.user returns the appropriate data.
I experienced this issue recently and was confused as well. I have figured out my code's specific problem so this is another potential solution.
I did not understand that #<UserSession: {:unauthorized_record=>"<protected>"}>
is still valid user session, just an unauthed one that we created ourselves. You can confirm this by calling user
on it and you should get whatever User
instance you passed into UserSession.create
.
The real issue is two fold. The current_user
method was built with the assumption that the current user would not change during the lifetime of a request and I was calling current_user
before creating one one to ensure I didn't have one already. It can be simplified to the following:
def current_user
return @current_user if defined?(@current_user)
@current_user = some_method_that_finds_a_proper_user
end
The key here is that my method for finding a user can return nil
. When it does, it will define @current_user
as nil
and thus that cached value will always be returned on subsequent calls.
Here's where it gets a bit harder as it really depends on what your code needs.
If you do not need the current_user
after signing a user model in with UserSession.create
then you don't need to do anything but wait for the render or redirect. On your next request, your current_user
will be properly set.
If you do not need to check for an already logged in user, remove any calls to current_user
before UserSession.create
if able and your first call to current_user
will work as expected.
Ensure your method chain that produces current_user
either does not use caching, does not cache nil
s, or change the guard for these cached values to determine if the value is truthy instead of if the instance variable is defined. The guard could be changed to:
return @current_user if !@current_user.nil? # or @current_user.present? in Rails
Or you can use Ruby's ||=
operator and implicit return. My simplified example above could instead be:
def current_user
@current_user ||= some_method_that_finds_a_proper_user
end
or if it's not as simple
def current_user
@current_user ||= begin
some_code
doing_many
things_here
end
end
Or your problem could be that you're having trouble writing a test for this behavior. In that case I'd rather just put an expectation on the code like
expect(UserSession).to receive(:create).with(user)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With