5 Replies Latest reply on Dec 14, 2012 11:58 AM by Jon Tara

    Call controller from another controller

    Gerbrand Stap

      This sounds like a simple question, but I haven't found a solution yet.

      In a controller method I have a callback url (e.g. "/app/MyController/action") and some data in a hash (e.g. { "param1" => "value1", "param2" => "value2" }) and I want to use these to call "MyController" with the hash in @params.

      I tried to use AsyncHttp, but that does not accept a relative url and RhoController.redirect does not accept any parameters to pass to the redirected action.


      Is there a method available in RhoMobile to trigger such a request?

        • Re: Call controller from another controller
          Jon Tara

          It's unclear what you are trying to accomplish. What does the target controller method do?


          It sound to me like you have written business logic in a controller. It belongs in a model, where it can be easily used from anywhere in your application.


          If you need to perform some kind of data storage/retrieval, business logic, etc. when the user presses a button, your controller should receive a message, and then not do that work itself. It should call a model method to do the work. That way, the data manipulation/business logic is not specifically tied to a controller.


          If you are not already familiar with MVC, the Rhodes docs are not a great place to start, since they offer few if any examples of adding your own code to models. IMO, models typically ought to grow more with your own code than controllers, but if you look at the Rhodes docs you'd think the opposite.


          (Although there is controversy currently about MVC with various people wanting to add another letter to the acronym to further-separate responsibilities so that business logic and storage are handled separately, Rhodes is MVC, so this is what we have to work with. In MVC, business logic belongs in the model.)


          That said, you can do timer callbacks with a timeout of 0 to invoke a request to a controller.

          1 of 1 people found this helpful
            • Re: Call controller from another controller
              Gerbrand Stap

              It a good thing to make use of the MVC model the way it should be done, but the problem I'm trying to solve is does not have anything to do with business logic.

              Discussions about how things should be done aside, the way to go are timers. I did not mention that one, but I already tried it and I did not yet succeed in passing more than one parameter to it.

              What I was trying to do is:

              1. Call some .Net web service using AsyncHttp, provide callback url to pass result to.
              2. In the callback do some generic processing (check status, get .Net exception and raise correct Exception if needed).
              3. On success: get data from response and pass to earlier mentioned callback url.

              The call would be needed in step 3, but I think I'll write some wrapper code around AsyncHttp instead, because my initial plan seems a little cumbersome.

            • Re: Call controller from another controller



              Will this serve your needs?


              url_for(:action=>'some_callback', :controller=>'AnotherController')





                • Re: Call controller from another controller
                  Gerbrand Stap

                  The url is already known at the point where the call needs to be done, so that is not what I need.

                  But I'm using an other approach now. I made a wrapper that makes it possible to pass the callback functionality in a block, like:


                  Wrapper.post( url, data ) { |response|
                       # do something with response


                  That is much neater than two callback after a http request.

                    • Re: Call controller from another controller
                      Jon Tara

                      I'm glad you found a solution, but I think perhaps you mis-understood my point.


                      Controllers have a specific role and usage. When the embedded server receives a request, it determines which controller is responsible for handling that request. It instantiates a controller object (for each request, individually, a new controller object) and calls the method associated with the request. When that request is completed, the controller object is destroyed.


                      Additionally, or coincidentally, Rhodes handles callbacks for things like timers, asyncHttp, etc. by making requests to the embedded server. You can argue that this is a good or bad approach, but is the approach we have, and it simplifies atomic access to resources.


                      Controllers are not a general-purpose repository for utility code. If you find that you want to access a controller method from within another controller, then you should refactor your code to move it out of the controller. Put it in SOME place outside of the controller. That might be inside a model, or in some other module or object. But not in the controller. (It's particularly convenient, though, to put it in a model, since you don't need to use require statements to access a model from anywhere in a Rhodes app.)


                      Now you can access that code using a normal Ruby function call. Just call it from both controllers - or from anywhere else in your Ruby code where you need to use it.


                      It is convenient during early development to add classes to controllers that are not actually meant to answer server requests, but it is a poor practice. If you do this as a convenience, find this code a proper home before you are done.


                      IMO, code in controllers should consist only of a very thin wrapper over code that lives elsewhere.