# How can I call a different controller from within a function

**URL:** <https://www.ruby-forum.com/t/how-can-i-call-a-different-controller-from-within-a-function/48150>\
**Category:** Rails\
**Created:** [November 17, 2005, 3:54am UTC](https://www.ruby-forum.com/t/how-can-i-call-a-different-controller-from-within-a-function/48150 "2005-11-17T03:54:27Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![smedberg](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c6cbf5/32.png) [@smedberg](https://www.ruby-forum.com/u/smedberg)\
**Post date:** [November 17, 2005, 3:54am UTC](https://www.ruby-forum.com/t/how-can-i-call-a-different-controller-from-within-a-function/48150/1 "2005-11-17T03:54:27Z")

</div>

> From within a controller test, I can call a function in the controller like  
> this:

get :index

but how do I call a function in a different controller?

I want to do this for a couple reasons.  
First I want to have my tests do a “real” login through my “user”  
controller.  
Second, my app supports redirects back to “where you were.” For  
instance, if  
a user goes to url A, then to url B, they might be redirected back to A.  
If,  
instead, they go to C, then to B, they’ll be redirected back to C. To  
test  
this functionality, I need to set the “original” URL by going to an URL  
in  
another controller (the A or C), then go to the URL in the controller  
under  
test, and see that the redirect is to the original controller.

I wrote some cheesy code to approximate the behavior I want. It looks  
like  
this:

class Test::Unit::TestCase  
#MES- Send an HTTP message to the indicated controller via

# the indicated method

def http\_to\_controller(method, controller, action, params)  
#MES- Store the current controller  
backup\_controller = @controller  
begin  
#MES- Swap in the indicated controller  
@controller = controller

#MES- Send the HTTP message  
self.send(method, action, params)  
ensure  
#MES- Swap back in the controller  
@controller = backup\_controller  
#MES- Remake the request, but save the session  
new\_req = ActionController::TestRequest.new  
new\_req.session = @request.session  
@request = new\_req  
end  
end  
end

and it can be called like this:

http\_to\_controller(:get, UserController.new, :show, { :id =\> user\_id })

But it doesn’t work quite right. In particular, the URLs are not always  
quite right, so a call to @request.request\_uri returns an old value (in  
this  
example, it wouldn’t return the URL to the UserController method, it’d  
return the URL to whatever the previous call was.

Any ideas? It seems like there’s got to be a cleaner and safer way to do  
this, but I haven’t been able to come up with it.

---

<div class="post-metadata">

**Author:** ![smedberg](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c6cbf5/32.png) [@smedberg](https://www.ruby-forum.com/u/smedberg)\
**Post date:** [November 17, 2005, 8:34am UTC](https://www.ruby-forum.com/t/how-can-i-call-a-different-controller-from-within-a-function/48150/2 "2005-11-17T08:34:53Z")

</div>

On 17.11.2005, at 4.53, Michael S. wrote:

> Second, my app supports redirects back to “where you were.” For  
> instance, if a user goes to url A, then to url B, they might be  
> redirected back to A. If, instead, they go to C, then to B,  
> they’ll be redirected back to C. To test this functionality, I  
> need to set the “original” URL by going to an URL in another  
> controller (the A or C), then go to the URL in the controller under  
> test, and see that the redirect is to the original controller.

You can split this up in parts.

In (say) posts\_controller\_test you test that the user is redirected  
to the login action in user controller, unless @session[:user]  
exists. You should also test that the “return address” is saved  
somewhere (probably session, too, or you can also use the referrer).

Then, in the user controller tests, you test that if the return  
address is set and login is valid, the user is redirected back to the  
correct place in the app.

Back in posts\_controller\_test, you then check that if @session[:user]  
exists, everything works fine without redirects to login system.

So you don’t really need to “go” to another url in your tests, as  
long as you can test that the needed session vars are set and that  
the redirection obeys them.

//jarkko

---

<div class="post-metadata">

**Author:** ![smedberg](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/c6cbf5/32.png) [@smedberg](https://www.ruby-forum.com/u/smedberg)\
**Post date:** [November 17, 2005, 12:30pm UTC](https://www.ruby-forum.com/t/how-can-i-call-a-different-controller-from-within-a-function/48150/3 "2005-11-17T12:30:15Z")

</div>

Hi there,

On 11/17/05, Michael S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> but how do I call a function in a different controller?
> 
> I want to do this for a couple reasons.  
> First I want to have my tests do a “real” login through my “user”  
> controller.  
> …  
> Any ideas? It seems like there’s got to be a cleaner and safer way to do  
> this, but I haven’t been able to come up with it.

I would suggest that you approach the problem in a different way. I  
find it much easier to test each controller/action in isolation from  
other actions. Where an action requires state from a previous action I  
pass the action in through the session parameter.

For example, most of the actions in my current application require  
authentication. A client is authenticated if a valid user\_id is stored  
in the session so that value needs to be in session for action to be  
successful. So an example where it is used would be the following that  
tests creation of a comment;

post(:new, {:comment =\>{:issue\_id =\> 1, :description =\>  
description}}, {‘user\_id’ =\> 1} )

You could invoke multiple actions from multiple controllers but I  
would suggest that this makes test evolution hard and less fine  
grained. Hope that helps!

–  
Cheers,

Peter D.  
[RealityForge.org](http://RealityForge.org): [http://www.realityforge.org](http://www.realityforge.org)
