Rails: Nested Resources routes not working - ruby-on-rails-3

I have the following routes defined:
resources :employees do
resources :questions
member do
get :results
end
end
One of the routes (rake routes) for the above resources prints this:
new_employee_question GET /employees/:employee_id/questions/new(.:format) questions#new
But when I do this = link_to 'New Question', :new_employee_question
I get the following error:
No route matches {:action=>"new", :controller=>"questions"}
I have both QuestionsController & EmployeesController defined with the required action methods.
I also tried the following in rails console:
Rails.application.routes.recognize_path(app.new_employee_question_path)
...which generates the following error:
ActionController::RoutingError: No route matches {:controller=>"questions"}
I am using Rails 3.2.6. Is there something I am doing wrong?

Try using this:
= link_to 'New Question', new_employee_question_path(#employee)

Related

Rails 3 No route matches {:action=>"show", error

While there are similar questions on this error, most relate to how Rails route handle pluralisation, whereas this is different.
I have a link on the 'show' view page within a controller called MemberPage which I need to link to the 'new' action within a controller called Post
<%= link_to ((content_tag :i, "", :class => "icon-pencil") + content_tag(:span, 'create')), new_members_community_post_path %>
Within routes I have
resources :post
which produces the following related line in rake routes
new_members_community_post GET /members/community/post/new(.:format) members/community/post#new
Hovering over the link shows
127.0.0.1:3000/members/community/post/new
Clicking on it produces the error
No route matches {:action=>"show", :controller=>"members/community/member_page"}
Rails is matching both the wrong controller and the wrong action from that shown in rake routes
I've tried creating explicit match rules in routes.rb, eg (within the members/community namespace)
match '/new-post' => 'post#new'
and also replacing the link_to path with
:controller => :post, :action => :new
but cannot find anything that works

explicit get route is throwing an error

I defined a custom route:
match 'folio/:id' => 'posts#show', :as => :folio, :via => :get
When I run rake routes command I have:
post GET /posts/:id(.:format) posts#show
folio GET /folio/:id(.:format) posts#show
And I put link for this element in my other page: link_to post.title, folio_path ,but when I enter it throws me an routing error:
No route matches {:controller=>"post", :action=>"show"}
Why it fails? When I'm using post#show in normal way it works like a charm, but with my custom route it fails - please help!
You need to specify the post so rails can fill the id part:
link_to post.title, folio_path(post)

Rails form_for with nested resources: "No route matches"

I have the following nested resources in my routes.rb file. The inner resource specifies a controller name.
resources :batches, :except => [:new], :path => "sets" do
resources :tags, :controller => "batches_tags"
end
In the view for BatchesTags#new, I am trying to build a form:
<%= form_for [#batch, #tag], :url => batch_tag_path do |f| %>
...
<% end %>
Attempting to load this page (/sets/1/tags/new) gives me a ActionController::RoutingError with the message:
No route matches {:action=>"show", :controller=>"batches_tags"}
But when I run $ rake routes, it clearly shows this route does exist:
batch_tag GET /sets/:batch_id/tags/:id(.:format) {:action=>"show", :controller=>"batches_tags"}
Does anyone know how to fix this error?
Edit:
In the view for Batches#show, I use that same batch_tag_path function and it works perfectly:
<%= link_to "...", batch_tag_path(#batch, tag) %>
It turns out that, while batch_tag_path is a valid route (making the "No route matches" error message very confusing), the path I needed was the pluralized batch_tags_path, as seen in this $ rake routes output:
batch_tags GET /sets/:batch_id/tags(.:format) {:action=>"index", :controller=>"batches_tags"}
POST /sets/:batch_id/tags(.:format) {:action=>"create", :controller=>"batches_tags"}
Perhaps the error message meant that batch_tag_path wasn't a valid route for POST?

Rails 3 nested resources short name?

I'm in the process of upgrading a Rails 2.3 app to Rails 3. In the Rails 2.3 router, it was possible to set a :name_prefix of nil on nested resources to get a shorter name. The actual URL would still be fully qualified, but the code could use a shorter name. E.g.,:
map.resources :sites do |site|
site.resources :groups, :as => :groups, :controller => :url_groups, :name_prefix => nil, :member => { :clone => :post } do |group|
group.resources :tests, :as => :tests, :controller => :test_runs, :name_prefix => nil, :collection => { :latest => :get }
end
end
would allow one to use latest_tests_path. I can't figure out how to do the same thing with Rails 3, so I'm stuck with latest_site_group_tests_path. If that's the way it needs to be, I can just go through the code and change every instance of it. But I wanted to make sure I didn't miss anything first. And for better or worse, I do need to maintain the URL structure, so shallow routes don't seem to be the answer.
Good news is that Rails 3 still has the ability to setup arbitrary/abbreviated url helpers. Rather than a parameter to the resources method, you can create short-hand url helpers with the match declaration in routes.rb.
Say we have routes setup like this (noting that you need to maintain the 3 levels of nesting):
resources :sites do
resources :groups, :controller => :url_groups do
member do
post :clone
end
resources :test_runs do
collection do
get :latest
end
end
end
end
We get all the standard url helpers (rake routes):
clone_site_group POST /sites/:site_id/groups/:id/clone(.:format) {:action=>"clone", :controller=>"url_groups"}
latest_site_group_test_runs GET /sites/:site_id/groups/:group_id/test_runs/latest(.:format) {:action=>"latest", :controller=>"test_runs"}
site_group_test_runs GET /sites/:site_id/groups/:group_id/test_runs(.:format) {:action=>"index", :controller=>"test_runs"}
(etc)
But to create something shorter than latest_site_group_test_runs_path(site,group), add a match declaration to routes.rb like this:
match 'sites/:site_id/groups/:id/test_runs/latest' => 'test_runs#latest', :as => :latest_tests
Now you can use latest_tests_path(site,group) or latest_tests_url(site,group) to generate the fully nested path.
If your aim is brevity, you could also use implicit polymorphic paths (as long as you have all your models aligned with resource paths).
For example, given #site #1 and #group #1, all of the following will now generate the same path '/sites/1/groups/1/test_runs/latest':
= link_to "latest tests", latest_site_group_test_runs_path(#site,#group) # std helper
= link_to "latest tests", latest_tests_path(#site,#group) # match helper
= link_to "latest tests", [:latest,#site,#group,:test_runs] # implicit polymorphic path
Hope that helps! Seems like you should be able to get the flexibility you need for the app migration.
NB: I glossed over the lurking issue of having a model called "Test" since that's off topic;-) There are a few model names that are a neverending source of pain because of namespace and keyword conflicts. My other favourite is when I really wanted to have a mode called "Case" (since that matched the problem domain best. Bad idea, rapidly reversed!)
There's the :shallow option (see the documentation), but I'm not sure it fits your use case:
resources :sites, :shallow => true
resources :groups do
resources :tests
end
end
It has the disadvantage of creating a bunch of additional routes:
group_tests GET /groups/:group_id/tests(.:format) {:action=>"index", :controller=>"tests"}
POST /groups/:group_id/tests(.:format) {:action=>"create", :controller=>"tests"}
new_group_test GET /groups/:group_id/tests/creer(.:format) {:action=>"new", :controller=>"tests"}
edit_test GET /tests/:id/modifier(.:format) {:action=>"edit", :controller=>"tests"}
test GET /tests/:id(.:format) {:action=>"show", :controller=>"tests"}
PUT /tests/:id(.:format) {:action=>"update", :controller=>"tests"}
DELETE /tests/:id(.:format) {:action=>"destroy", :controller=>"tests"}
site_groups GET /sites/:site_id/groups(.:format) {:action=>"index", :controller=>"groups"}
POST /sites/:site_id/groups(.:format) {:action=>"create", :controller=>"groups"}
new_site_group GET /sites/:site_id/groups/creer(.:format) {:action=>"new", :controller=>"groups"}
edit_group GET /groups/:id/modifier(.:format) {:action=>"edit", :controller=>"groups"}
group GET /groups/:id(.:format) {:action=>"show", :controller=>"groups"}
PUT /groups/:id(.:format) {:action=>"update", :controller=>"groups"}
DELETE /groups/:id(.:format) {:action=>"destroy", :controller=>"groups"}
sites GET /sites(.:format) {:action=>"index", :controller=>"sites"}
POST /sites(.:format) {:action=>"create", :controller=>"sites"}
new_site GET /sites/creer(.:format) {:action=>"new", :controller=>"sites"}
edit_site GET /sites/:id/modifier(.:format) {:action=>"edit", :controller=>"sites"}
site GET /sites/:id(.:format) {:action=>"show", :controller=>"sites"}
PUT /sites/:id(.:format) {:action=>"update", :controller=>"sites"}
DELETE /sites/:id(.:format) {:action=>"destroy", :controller=>"sites"}
Besides, the shallow nesting only applies to the following routes: :show, :edit, :update, :destroy.
I wanted something like this too, clearly it feels redundant to type the prefixes in named routes all the time for resources that only exist as nested. I was able to get what I wanted using scope, I think this is what you sought too:
resources :sites
scope :path => '/sites/:site_id' do
resources :groups, :controller => :url_groups do
post :clone, :on => :member
end
end
scope :path => '/sites/:site_id/groups/:group_id' do
resources :tests, :controller => :test_runs do
get :latest, :on => :collection
end
end
The rake routes output:
sites GET /sites(.:format) sites#index
POST /sites(.:format) sites#create
new_site GET /sites/new(.:format) sites#new
edit_site GET /sites/:id/edit(.:format) sites#edit
site GET /sites/:id(.:format) sites#show
PUT /sites/:id(.:format) sites#update
DELETE /sites/:id(.:format) sites#destroy
clone_group POST /sites/:site_id/groups/:id/clone(.:format) url_groups#clone
groups GET /sites/:site_id/groups(.:format) url_groups#index
POST /sites/:site_id/groups(.:format) url_groups#create
new_group GET /sites/:site_id/groups/new(.:format) url_groups#new
edit_group GET /sites/:site_id/groups/:id/edit(.:format) url_groups#edit
group GET /sites/:site_id/groups/:id(.:format) url_groups#show
PUT /sites/:site_id/groups/:id(.:format) url_groups#update
DELETE /sites/:site_id/groups/:id(.:format) url_groups#destroy
latest_tests GET /sites/:site_id/groups/:group_id/tests/latest(.:format) test_runs#latest
tests GET /sites/:site_id/groups/:group_id/tests(.:format) test_runs#index
POST /sites/:site_id/groups/:group_id/tests(.:format) test_runs#create
new_test GET /sites/:site_id/groups/:group_id/tests/new(.:format) test_runs#new
edit_test GET /sites/:site_id/groups/:group_id/tests/:id/edit(.:format) test_runs#edit
test GET /sites/:site_id/groups/:group_id/tests/:id(.:format) test_runs#show
PUT /sites/:site_id/groups/:group_id/tests/:id(.:format) test_runs#update
DELETE /sites/:site_id/groups/:group_id/tests/:id(.:format) test_runs#destroy
Update: Duh, I left the static segments of the scope paths out of my example. Fixed.

NoMethodError - undefined method

I'm having problems displaying data from a separate controller. I have a number of users, each with many pages. I've followed this tutorial with a few minor adjustments.
The error that keeps appearing is:
NoMethodError in SitesController#show
undefined method `page' for #<ActionDispatch::Request:0x00000102452d30>
My routes.rb is as follows:
devise_for :users
resources :users, :only => [:index, :show] do
resources :pages, :shallow => true
end
match '/' => 'sites#show', :constraints => { :subdomain => /.+/ }
root :to => "home#index"
And I have a sites controller:
class SitesController < ApplicationController
def show
#site = Site.find_by_name!(request.page)
end
end
I've also tried:
def show
#site = Site.find_by_name!(params[:site])
end
Which gives a different error.
Am totally stuck trying to figure this out!
Looking forward to your assistance.
Bob
The problem is here: request.page
The request object is of the class ActionDispatch::Request, which does not have a page method.
To track down errors like this, you can try either looking at the docs or messing around in the debugger.
Try running your controller with --debugger enabled.
If you are running Ruby 1.8, install the ruby-debug gem.
If you are running Ruby 1.9, install the ruby-debug19 gem.
Add a debugger call here:
class SitesController < ApplicationController
def show
debugger
#site = Site.find_by_name!(request.page)
end
end
Run your server with the --debugger option.
See what p request.page does. I bet it will have an "undefined method" error, just you see when you try to view that controller action.
If you do a p request.class you can find out what class the object is, and then look up the docs to see how to use it.