How can I call another controller's action (or better yet, how do I force a POST)?

I've got an action that runs, and when it's done I want the user to POST to another URL. However I don't want to display a form that they need to submit.

The two ideas I've had are to either call OtherController#create directly, or to send some response to the browser that initiates a POST back to the correct URL.

Anyone know how to do this, or have any other ideas?

Pat

Hi Pat,

Pat Maddox wrote:

I've got an action that runs, and when it's done I want the user to POST to another URL.

I haven't tested it with the POST, but maybe just...

redirect_to :controller => controller_name, :action => action_name, :method => "post"

If redirect_to won't take the POST, you could maybe query controller.controller_name and/or controller.action_name to see where the request came from and then treat it accordingly.

hth, Bill

check out

http://drawohara.tumblr.com/post/2070878

-a

AFAIK, HTTP doesn't allow redirects using the POST method... which makes sense. A redirect is either a "302 Found" or a "301 Moved Permanently", usually the former. Either of these are saying "you asked for a resource, but it's not here... *here* (the Location header) is where to get it." Nothing about form submission. Redirects are always GETs.

If you want the form data to be processed as a POST in a different controller and originating from the client, I think javascript is about your only option. You can use the rails prototype library to send a post from within javascript and without showing a form to the user. I've done this many times.

However, I'm not sure that that's what you really want. What is it that the first action is doing? Was it handling a form submission? If the problem is that you have some logic in one action that you need in two places, then you could pull that out into a helper method in application_helper. You can also do common side-processing in filters.

I haven't done your idea of calling an action from within another action, but that might work. Just remember that is a regular method call, so control will return to the caller after the called action is done. And you can only call render in there once, so you'd need conditionals around the render calls if there's more than one.

Well, I hope something in there helps...

Ben

The user goes through a workflow, updating a db record in a series of steps. When the whole thing is done, we create another record (of a separate class).

The problem is that sometimes they have a final Preview step and sometimes they don't. When the user has a preview step, I show a filled in form. They submit it, our record is created, all is good. When they don't have a preview step though, we never see this page. So I have to handle it before that, when they complete the final step of the workflow.

So basically they same logic goes in the VideosController#create method and the final step of the workflow. That sucks.

I think a *reasonable* approach is, if the user doesn't have a preview step, redirect them to a blank page that has the form in it. Use page.onload to automatically submit the form. This way I keep all the final creation logic in one place.

Thoughts?

Pat

why not just call the create method and return when the user doesn't need to see the preview?

def final_step   ...   create() and return   ... end

the whole js onload thing seems a bit gnarly!

worse case... to DRY things up... I would say just put the logic in a shared module and call it from your controller methods?

good luck! Tim

I need to run a couple more statements than just the create. It's creating associated objects, but I don't think it should be done as part of a create hook. There's only like three lines that need to be duplicated. So I guess I'll move it into a module.

I think I might be missing something though. So let me give a bit more detail.

class Video < AR   has_many :assets end

class Asset < AR; end

The create is going to be a simple @video = Video.create params[:video]

From here I need to create a couple assets. I *could* just do this in a create hook, except for the fact that I need to pass them a frame number. This never gets stored anywhere but gets sent back to a transcoding server.

So I feel weird about putting a frame_number accessor on either Video or Asset. They'd only ever use it once, and it just seems like it shouldn't go there.

Doing this all in a create hook would also make testing tougher because I'd have to stub lots of stuff.

I *think* what I should do is write a new builder/method or class that handles all of this. I can call that method, passing it all the info I need, and it will create the video, the assets, and tell the other server about it. That way I can encapsulate the entire building process by one method, so I don't have any duplication, and my AR classes stay lightweight and don't have to worry about constructing all these other things.

Sorry if that's a bit rambly, it's basically me talking things through. Thanks for listening :slight_smile:

Pat

I'd do this in the Video model, even if it touches things (like frame_number) that don't get persisted to a database, it sounds like a create_with_assets method that does what you say will just implement your "business rules" where a video needs to be created together with those assests under some circustamces (and just having a "fat" model is not bad if it helps to better define the domain model and its associated rules)

just my 2c.

Luca Mearelli