views:

27

answers:

2

Let's say you have a form that has its own controller. Is there any way to embed this form in different views (governed by other controllers)? As far as I understand partial templates carry only logic in the Ruby code that is inside the template. I am thinking more of a full-blown component where maybe somehow you can call its controller or something like that.

+1  A: 

The form is not driven that directly by the controllers. Yeah this is the price of all this magic.

To clarify a bit:

  • You type in your browser http://yourhost/posts
  • Your request (GET /posts) hits the router, then your router says that the /post urls belongs to the PostsController and the action is index
  • Then your controller executes the index method, do your business logic (loads the posts from the database, for example)
  • loads the view (views/posts/index...) and run it by 'substituting' all the instance variables and stuff defined in your controller (eg @posts = Post.all) that you have in it
  • then you see the view rendered with a list of posts (if in the view you have something similar to @posts.map{|p| p.title}.join(", ") )

yes I know it's not the best /posts view in the world but it's only to grasp the idea

The same goes for form, your form tag (for example form_for) gets an instance from the controller (let's say @post) and (in edit mode) gets filled with your Post attributes. Then when you (edit something and) click the submit button it makes a request (by default a PUT to /posts) passing all the values in the form, then your controller gets the (POST) values of the requests (the ones you see in the server log) and makes his work (like saving the post's datas)

and because of this in a controller you can use the method

render :controller => :foo, :action => :bar

to render another controller action different from the default one

Hope this will be useful!

makevoid
You mean you pass an object like @post to the form which is in your case just a partial template?Once the server gets the POST values how does it know what to do with them? Sorry for the basic questions..
Fortress
Thanks for the explanation! I wonder if anyone has other approaches? The problem though is that the action :bar might change across the site. Then you have to change it in each controller where you have the form.
Fortress
I should've used another name instead of posts :), well... The html form generated from the rails helpers and has an action and a method, for example: <form action="/comments" method="post">; so when you submit it it will make a POST request to the '/comments' url, if you have a CommentsController with an update action, that request will hit it and execute it and it's up to you to tell the server what to do with the values recieved (you have them in the params hash inside of the controller's action)
makevoid
So, when I have action="/comments" the request will be processed by the CommentsController. What if I have this form under the /posts URL. Now that a different controller is working will it change my current page necessarily? When I process params in /comments can I change the partial template of the form immediately afterwards? I guess I could just redirect to /posts (homepage) with new values or something like that.
Fortress
+1  A: 

You can create a form in any view to call any controller. In a RESTful app, you can usually just pass an empty object (using the Posts/Commments example from makevoid)

 <% form_for @new_comment do |f| %>
   <%= f.text_area :text %>
   <%= f.submit %>
 <% end %>

This form should route to the create action on CommentsController. From there, you could use redirect_to :back in order to get back to the view that triggered this controller. This does have some validation issues I think though.

If you are non-RESTful, you can use the old form_for style:

 <% form_for :comment, @new_comment, :url => { :controller => "comments", :action => "create" } do |f| %>
   <%= f.text_area :text %>
   <%= f.submit %>
 <% end %>

For either of these examples, you need to have the @new_comment, which you would create in your PostsController:

 def show 
   @post = Posts.find(params[:id])
   @new_comment = @post.comments.build
 end
jamuraa