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 "sessi开发者_如何学编程ons", ["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.
tl;dr
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
.
Cause
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.
Solutions
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 withUserSession.create
then you don't need to do anything but wait for the render or redirect. On your next request, yourcurrent_user
will be properly set.If you do not need to check for an already logged in user, remove any calls to
current_user
beforeUserSession.create
if able and your first call tocurrent_user
will work as expected.Ensure your method chain that produces
current_user
either does not use caching, does not cachenil
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)
精彩评论