Ruby Authlogic: lazy initialization based on defined?() call
What is the difference between following two versions of code?
# Version: V1 def current_user_session return @current_user_session if defined?(@current_user_session) @current_user_session = UserSession.find end
This is very similar to following code:
# Version: V1 def current_user_session unless @current_user_session @current_user_session = UserSession.find end @current_user_session # the above code could also be written as: @current_user_session ||= UserSession.find end
The difference is that V1 optimizes the code is by making that expense “UserSession.find” query only once per lifetime of enclosing class (which, if you’ve used authlogic, you recognize that it is the ApplicationController class). Then V2 version is a bit inefficient in that if the UserSession.find happens to be nil (when the user is not logged in), it continues to call UserSession.find each time this method is called. Fair enough.
However, this messes up your test if you aren’t writing your test with this fact (the first call to current_user_session method will fix the value of @current_user_session and cannot be changed for the entire test run) in mind.
Consider this test, which passes:
# Test for when "logout" is invoked, the user-session is properly destroyed and user is redirected context "with a logged-in user" do setup do User.create(:username => "foo", :email => 'foo@company.com', :password => "secret", :password => "secret") UserSession.create(:username => "foo", :password => "secret") assert controller.logged_in? end should "destroy session and redirect to root page on logout" do post :destroy assert_nil(UserSession.find) assert_redirected_to root_url end end
Now, if you introduce a print statement to print the current_user_session after the user is logged in, it will mess up the test and your test will fail:
# Test for when "logout" is invoked, the user-session is properly destroyed and user is redirected context "with a logged-in user" do setup do User.create(:username => "foo", :email => 'foo@company.com', :password => "secret", :password => "secret") # The following line is to make sure user is not logged in initially # However, this line will end up calling controller.current_user_session and will fixate @current_user_session to nil for the rest of the test !!! assert_nil controller.logged_in? UserSession.create(:username => "foo", :password => "secret") assert controller.logged_in? end should "destroy session and redirect to root page on logout" do post :destroy assert_nil(UserSession.find) assert_redirected_to root_url end end
I can see the reasoning for V1 but I still prefer V2, even though it is little ‘inefficient’.
Related posts:
- Working with Authlogic in script/console When probing / debugging issues with Authlogic on rails console,...
- Authlogic: after the initial hype On my rails projects, I’ve used restful_authentication before and I...
- Getting session_id in rails If you are using database sessions, rails sessions table stores...
- Environment specific routing in rails For better application support, it is usually nice to build...
- Login as multiple users simultaneously for testing Ever wondered how to login as two different users...
Related posts brought to you by Yet Another Related Posts Plugin.





