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.
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!
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