How to "call" controller from elsewhere in the app?

Is there a way to "call" a controller from another part of the app?

I'm breaking off some functionality (statistics reporting) from the
rest of the app. Eventually, this functionality will live in a
different app, but for ease of development, I'd like to keep
everything in the same app for now. So the stats client (a lib class)
would like to do a "get" on the stats controller in the same app.

I can't use render_component, because I'm not in a view/controller. I
apparently can't use ActionController::Integration::Session because,
while it works fine in RSpec tests, when I use it under mongrel, I get
a stack overrun when I require 'action_controller/integration'.

I'd like to put off maintaining two applications for as long as
possible. Any thoughts?

///ark

(Hmmm...can I just instantiate the controller? I'll try that.)

Mark Wilden wrote:

Is there a way to "call" a controller from another part of the app?

Refactor the shared code into a Model or a class in the lib folder.
Period.

Sorry, I didn't make myself clear, I guess (and I think you may have
jerked a knee based on the subject line). At some point, the code will
indeed "call" a controller, but it'll be in a different app. That
controller will call the actual lib code. There's zero logic in the
controller - just some parameter massaging. I just want to get as
close as possible to the eventual way the app will work, where one
controller creates a lib object, which calls another controller (or
does a GET on a URL), which calls more lib code. It has nothing to do
with shared code - there is none.

My workaround is simply to have the client object talk directly to the
server object (since they're in the same app), rather than mediating
the conversation through a controller (which is what will eventually
happen).

But my question remains: Is it possible to "call" a controller when
running under mongrel, as is done with render_component and
ActionController::Integration::Session (not to mention the Rails
console)?

///ark

(Nice to see you're on Rails, Phlip! You probably don't remember me,
but we've been conversing on one list or another for ten years or so.)

Judging by the responses, I guess the answer is "no." :slight_smile:

///ark

Hi,

An interesting alternative which _may_ suit your Use Case is the new
ActiveResource capability. You could potentially string your
applications together as a set of REST services. Refactoring the code
as per Philip's "response" is appropriate when business logic manages
to sneak into controller or view.

My advice is to ignore Rails for a while and focus on how Ruby
packages shared logic.

Good luck!

Chris

An interesting alternative which _may_ suit your Use Case is the new
ActiveResource capability.

Thanks for the reply, Chris. ActiveResource is one possible way to
communicate between the two applications. I think for my needs,
though, simply marshalling the objects will be good enough to bridge
the gap. However, that has absolutely nothing to do with my
question. :slight_smile:

My advice is to ignore Rails for a while and focus on how Ruby
packages shared logic.

This doesn't involve shared logic. I'm clearly doing the world's worst
job explaining myself.

The architecture will have two Rails apps (call them StatsClient and
StatsServer) on two machines. One app will ask the other app for data.
No shared logic.

However, while I develop this, I'd like to keep everything in one app
for as long as possible. But even with one app, I'd still like to
exercise the StatsServer controller, because it does some marshalling.
So ideally, StatsClient would do a GET from StatsServerController,
even though (for now) they're in the same app. That's all I want to
do. That way, when I do split out the two applications, very little
code needs to change.

This is not an architectural question. It's a request for a solution
to a temporary need (expressed in the subject line), which is purely
for developer convenience until the point where the two apps are
separated properly.

///ark

Make use of Ruby’s net\http library to make the call. This is off the top of my head…

Probably the best thing to do is make a model to create the call

class RemoteRequest

require 'net/http'

def self.get(your_url)
url = URI.parse(your_url)
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) {|http|
http.request(req)
}
return(res.body)

end

Then use it.

body_to_parse = RemoteRequest.get(“http://www.google.com/”)

The reason I say to use a model is that you can refactor just this method later to use a different method.

Remember - Rails is built on Ruby. Make use of the various Ruby libraries out there to get stuff done if Rails doesn’t do it for you.

Thanks, Brian. This is what I had in mind for the final structure,
when the client app and the server app are split in two. I appreciate
the code.

The problem is that this won't work to call the -same- Rails app,
since mongrel blocks new requests until the current request is
completed. Or so I understand, at least.

///ark

Thanks, Brian. This is what I had in mind for the final structure,
when the client app and the server app are split in two. I appreciate
the code.

The problem is that this won't work to call the -same- Rails app,
since mongrel blocks new requests until the current request is
completed. Or so I understand, at least.

That is true. You could of course have two instance of mongrel running, and make sure these inner requests only go to the second one.

Fred

Interesting. Then I could use code like Brian's to simply do a GET
from the same app on a different port. Cool.

This wouldn't be workable in production (introducing new mongrels for
a month or so). But it's something I hadn't considered. Thanks!

///ark