logo logo

Forms With Nested Resources In Rails

This post is more of an informational post for myself in case I forget this later on. I have been working on a client project thats using Ruby on Rails and I was having a little trouble getting my head around nested resources and the routing that goes along with that. Once I had the routing figured out, the next thing to address was handling my forms. Now, as with all things in programming, there is more than one way to "skin a cat" when it comes to this in Rails but for the most part, this is from what I can tell, the preferred method and I like it better than the alternative.

To start off with, nested resources is simply a way to have much cleaner urls without having to append a query string to the url. So you can have something like:

mysite.com/category/1/products/3

instead of:

mysite.com/category/1?product=3

Of course the nice URL's are not the only reason for doing this. When it comes to handling forms, Rails can handle all of the associations for you reducing the amount of code you are writing.

So, borrowing form the earlier example of products and categories, we can easily setup our form to handle the relationship by modifying our form_for arguments in the form like this:

form_for [@category, @product] do |f|

Now we no longer have to manually add a hidden field containing the category id.

In our controller, several methods are affected by this change, but lucky for us the changes are simple.

First, lets look at the new method which sets up the blank form:

def new
@category = Category.find_by_id(params[:user_id])
@product = @category.build_product
respond_to do |format|
format.html
end
end

Since we are referencing the product through the category, its best to use the category itself to build the new product object. This allows the previous change that we made to the form to work. Now lets have a look at the create method that will actually save our form:

def create
@category = Category.find_by_id(params[:user_id])
@product = @category.build_product(params[:product])
respond_to do |format|
if @product.save
flash[:notice] = 'Product was successfully created.'
format.html { redirect_to edit_category_product_path(@category,@product) }
else
format.html { render :action => "new" }
end
end
end

Notice again that we are building the product object through the category association and passing the product data to it from the form to populate it. Thats pretty much all of the magic sauce. There is one other thing to notice in that method that warrants attention. Notice the redirect_to method? Normally that would look something like this:

redirect_to edit_product_path(@product)

But since we are accessing products as a nested resource of categories, we simply add in the category part to the method and supply the category instance variable to the argument list. This will ensure we are redirected to the proper url.

Now I know this is a dumbed down version of this, but hey, like I said earlier, its more for my reference later on. Hopefully someone can get something out of it as well.

 

 

bottom

Leave a comment