Forum: Ruby on Rails functional testing with logging in

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
surge (Guest)
on 2007-07-01 04:32
(Received via mailing list)
Hello,

One of the actions in one of my controllers requires a login and I'm
trying to write a test for that action. I don't want to actually go
through the login process. I just want to initialize a session
variable and be done with it :)

So, the way the authentication works is pretty simple. In my
application controller I defined this method:

  def authenticate
    if session[:user].nil?
      session[:initial_uri] = request.request_uri
      redirect_to :controller => 'user', :action => 'login'
    end
  end

In the controller, I have :before_filter = "authenticate"

Now, my test so far is:

  def test_show_valid_request
   # Assign the user session variable the user with id = 1
    @request.session[:user] = User.find(1)

   # Santity test -- this does say that the value is an ActiveRecord
object.
    puts @request.session[:user]

    # Try to call the action, which triggers a call to authenticate
    get :show, { :id => '1' }, { :customer_id => '16' }

    # This should fail because no redirection should take place
    assert_redirect_to(:controller => 'user', :action => 'login')
 end

What happens is that the "if session[:user]" in "authenticate" returns
nil.

tail -f on logs/test.log has "Session ID: ", which would mean that no
session exists?

Anybody know what I'm missing?
Daniel -. (Guest)
on 2007-07-01 15:40
(Received via mailing list)
On 7/1/07, surge <removed_email_address@domain.invalid> wrote:
> application controller I defined this method:
> Now, my test so far is:
>     get :show, { :id => '1' }, { :customer_id => '16' }
>
> Anybody know what I'm missing?



Because your using a before filter, and the session variable is set
there is
not actually anything being evaluated for the method.  Hence the last
evaluated expression for the method is nil.

If at the end you returned the session[:user] it should work.

  def authenticate
    if session[:user].nil?
      session[:initial_uri] = request.request_uri
      redirect_to :controller => 'user', :action => 'login'
    end
    session[:user]
  end


There are dangers associated with storing your user object in the
session.
Stale objects and more.  There is plenty of discussion about it on the
list
and elsewhere.  It is common practice to just store the ID of the user
object in the session and then do a lazy lookup of the user when you
need
it.  It only results in one lookup per request for the user object.

eg something like

def current_user
  @current_user ||= User.find_by_id( session[:user_id] ) if
session[:user_id]
end

HTH
Daniel
surge (Guest)
on 2007-07-01 17:08
(Received via mailing list)
>  Because your using a before filter, and the session variable is set there is
> not actually anything being evaluated for the method.  Hence the last
> evaluated expression for the method is nil.

Hmm, I don't think that's it because I'm not relying on the return of
value of "authenticate". It just redirects or doesn't. And it does
redirect, which means that session[:user] is nil by the time
authenticate is called. But if I do this:

get :show, { :id => '1' }, { :user => User.find(1) }

it does work. So, for some reason if the session variable is set as
part of the get call, it works.

> There are dangers associated with storing your user object in the session. Stale objects 
and more.

Thanks for the tip. I'll rework my process to take that into account.
Never thought about it!

Thanks for the post, Daniel.
Daniel -. (Guest)
on 2007-07-01 17:57
(Received via mailing list)
On 7/1/07, surge <removed_email_address@domain.invalid> wrote:
> authenticate is called. But if I do this:
> Never thought about it!
>
> Thanks for the post, Daniel.



In IRB

?> def test
>> if @test.nil?
>>   "Blah"
>> end
>> end
=> nil
>> test
=> "Blah"    # => When @test is not set the method returns a value
>> @test = "I'm Set"
=> "I'm Set"
>> test
=> nil #=> When @test is set the method returns nil
>>

Can you see that in your situation, when your session variable is set
the
method will return nil?

From the docs you can see.
http://api.rubyonrails.org/classes/ActionControlle...

before_filter<http://api.rubyonrails.org/classes/ActionControlle...
around_filter<http://api.rubyonrails.org/classes/ActionControlle...
halt the request before controller action is run. This is useful, for
example, to deny access to unauthenticated users or to redirect from
http to
https. Simply return false from the filter or call render or redirect.


So if the result of a method evaluates to false ( either false or nil )
then
the action of the controller will not be run.  Since your redirect_to is
inside an if statement whose body is never executed it does not
re-direct
either.   So even though you aren't explicitly relying on the return
value
of authenticate, rails is as part of the before_filter behavior.

I've never actually tried this.  What is returned in this situation?

Daniel
surge (Guest)
on 2007-07-01 20:20
(Received via mailing list)
> Can you see that in your situation, when your session variable is set the method will 
return nil?

If I do @request.session[:user_id] = 1, the "if session[:user].nil?"
returns true and the redirect does happen.
If I do get :show, { :id => '1' }, { :customer_id => '16' }, the
method does return nil, but the action of the controller is not
stopped.

That's interesting about halting the action of a controller. It's
strange though. Say I do return false from a before filter, what would
the user see?

I'm not a big expert on all this -- just reporting the results.

Sergei
Steve R. (Guest)
on 2007-07-01 22:05
(Received via mailing list)
There is a better way (IMO). Move as much authentication as possible
into your model, then create a logged_in? helper function in your
application.rb. For your tests, use Mocha (http://
mocha.rubyforge.org/) and stub the logged_in? function to return true
for tests where the user is meant to be logged in and false for ones
where you might have a bogus user.

E.g.,

# your controller
def test_user_is_logged_in
   controller.stubs(:logged_in?).returns(true)
   # ...
end

Just a thought...


On Jul 1, 2007, at 9:19 AM, surge wrote:

> That's interesting about halting the action of a controller. It's
> >
Steve R.
removed_email_address@domain.invalid
http://www.calicowebdev.com
surge (Guest)
on 2007-07-01 22:53
(Received via mailing list)
Steve, thanks for the idea. Right now though I want to stick to the
framework so I can keep the amount of new information to a minimum :)
Steve R. (Guest)
on 2007-07-01 23:11
(Received via mailing list)
Here is some code from one of my older projects:

   # in controller
   def test_admin
     get_logged_in
     get :admin
     assert_response :success
   end

   # in test_helper.rb
   def get_logged_in
     request.session[:user] = users(:users_004).id
     # theoretically, there is more involved in getting logged in...
i.e., login time
   end

Hope this helps.

On Jul 1, 2007, at 11:51 AM, surge wrote:

>> where you might have a bogus user.
>>
>>> returns true and the redirect does happen.
>>
>>> Sergei
>>
>> Steve R.
>> removed_email_address@domain.invalid://www.calicowebdev.com
>
>
> >

Steve R.
removed_email_address@domain.invalid
http://www.calicowebdev.com
surge (Guest)
on 2007-07-02 03:13
(Received via mailing list)
Yes, that's what I was doing too -- except are you sure it's
"request.session[:user] = users(:users_004).id" and not
"@request.session[:user] = users(:users_004).id"? Because otherwise I
get "an unknown local variable". Anyways, this general approach is not
working for me for some reason. But I'm OK with passing the session
variables along with the call to "get"

Thanks!
Sergei
This topic is locked and can not be replied to.