## Friday, October 5, 2012

### Rails Namespace, Nested Resource and form_for

Couple days ago, I ran into a problem when I try to use namespace, nested resources and form_for in Rails 3 and ruby 1.9.3. I try to setup some thing similar to this, a namespace :admin, with nested resources :menus, and :menu_items. Here is the routes.rb:
namespace :admin do
end
end
I think it's probably common used case. Unfortunately, I got this error when I try to create a new MenuItem in menu_items/_form.html.erb
undefind method 'admin_menu_items_path' for #<#<Class ...
...
...
17: end

I realize that the standard scaffolding won't work for me, so I start googling. Right away, I get a lot of hits. It's seem to be a common issue. However, the solutions create quite a confusion for me. I try different solutions, some looking good but don't work! .. Here is what I find working.

def new
...
end

It load up the @menu, and build @menu_item, nothing surprise me. I also get rid of than "admin" prefix. It's simpler that way.

Next, I move form_for statement, from the partial _form.html.erb to new.html.erb. Here the form_for statement in new.html.erb looks like:
...
<%= render :partial => 'form', :locals => { :f => f } %>
<%= end %>
...

I pass [@menu, @menu_item] as the first argument of form_for. That make sense to me because of the nested resources. However, this is not enough to handle namespace. To do so, I need to specify :url, which usually infer from the first argument of form_for. Unfortunately auto generate routing doesn't work here, probably because of the namespace.  By far, specifying :url the cleanest solution I have seen.

I have to move form_for because the partial _form.html.erb is also used by edit.html.erb. Since this solution require to specify :url, the line form_for can not be in the _form.html.erb any more.

One other thing, to pass variable f as local variable to partial _form.html.erb, you need the keyword :partial there. I still don't understand this line doesn't work!
<%= render 'form', :locals => { :f => f } %>
Why won't render 'form' take :locals options the same way as render :partial => 'form' does? It's a mystery to me.