I have a model called Contributor, which also acts as a namespace for several other models, such as Contributor::Alias and Contributor::Reassignment. I want to use a URL that includes the Contributor ID like so:
/contributors/1/reassignments/new
But I get this error:
No route matches [GET] "/contributors/1/reassignments/new"
My routes.rb file includes:
namespace :contributor do
resources :reassignments
end
resources :contributors
I've also tried:
resources :contributors do
resources :reassignments
end
This results in a different error:
uninitialized constant ReassignmentsController
Any idea how to approach this? Perhaps I shouldn't use a namespace that also acts as a model? I haven't seen this done in any tutorials, though it seems like it could be possible.
UPDATE:
How do you handle a deeply nested namespace model, such as:
resources :contributors do
resources :reassignments, :module => "contributor" do
resources :approvals, :module => "reassignment"
end
end
Using this approach, I get the error:
No route matches {:action=>"create", :controller=>"contributor/reassignment/approvals"}
My controller directory does have the following structure:
contributor ->
reassignment ->
approvals_controller.rb
This seems related to the first error, but perhaps it's something new.
It's not clear if you have a Contributor resource or not. If you do, the following in your routes.rb:
resources :contributors do
resources :reassignments, :module => "contributor"
end
If not, try:
resources :reassignments, :module => "contributor", :path => "/contributors/:contributor_id/reassignments"
Just note that in the 2nd case you will need to construct an url and explicitly pass :contributor_id to it in calls to link_to, form_for, and similar places.
If you want to use [#contributor,#reassignment] format there you better stick to the 1st approach where yu do have a Contributor resource.
UPDATE: for three-level nesting if your controllers directories don't also nest in parallel with resources you could specify controllers explicitly, e.g.:
resources :contributors do
resources :reassignments, :controller => "contributor/reassignments" do
resources :approvals, :controller => "reassignment/approvals"
end
end
But, please, don't do that. 3-and-more-level nesting is actively discouraged in Rails. See what is recommended instead here: http://weblog.jamisbuck.org/2007/2/5/nesting-resources
Related
I have 3 resources that are structured in a hierarchy as follows:
house 1-* residents 1-* books
We know that its not great to have deeply nested routes, so we endeavour to have routes nested at most 1 resource deep. Defined something like:
resources :houses do
resources :residents
end
resources :residents do
resources :books
end
The problem is that we end up defining :residents as a resource that can be accessed without any nesting - as part of the definition of :books. Is there way to define :books as being nested in :residents, without inadvertently registering :residents as a top level route?
This can be accomplished by using scopes, in your case:
scope 'residents/:resident_id' do
resources :books
end
However, as I mentioned in the comment, this practice can end up confusing users who expect URLs to behave in a certain way (deleting the last bit takes them up a level).
In my models have accommodations that belong to a locality. With friendly_id my resourceful routes would look like this:
/localities
/localities/:locality-name
/accommodations
/accommodations/:accommodation-name
The problem is that I'd like to have the accommodation detail URL look like:
/accommodations/:locality-name/:accommodation-name
and also have a locality filter for accommodations:
/accommodations/:locality-name
Naturally I can add the following to routes.rb:
resources :localities do
resources :accommodations
end
... which would result in:
/localities/:locality-name
/localities/:locality-name/accommodations
/localities/:locality-name/accommodations/:accommodation-name
But I would like the accommodations to begin with /accommodations and not get nested under localities.
The closest I got is by modifying the above to this:
resources :localities, :path => 'accommodations' do
resources :accommodations, :path => '', :except => :index
end
This does what I want, but turns things upside down and sort of messes up both my resources. Additionally I could add resources :localities, :path => 'localities' to routes.rb but then the localities index view would appear for both /localities and /accommodations. And I would like these URLs to act as some sort of portals for the stuff they stand for.
So, should I give up on resourceful routes? Or is there a solution?
Thanks.
i have a namespace "shop". In that namespace i have a resource "news".
namespace :shop do
resources :news
end
What i now need, is that my "news" route can get a new parameter:
/shop/nike (landing page -> goes to "news#index", :identifier => "nike")
/shop/adidas (landing page -> goes to "news#index", :identifier => "adidas")
/shop/nike/news
/shop/adidas/news
So that i can get the shop and filter my news.
I need a route like:
/shop/:identfier/:controller/:action/:id
I tested many variations but i cant get it running.
Anyone can get me a hint? Thanks.
You can use scope.
scope "/shops/:identifier", :as => "shop" do
resources :news
end
You will get those routes below:
$ rake routes
shop_news_index GET /shops/:identifier/news(.:format) news#index
POST /shops/:identifier/news(.:format) news#create
new_shop_news GET /shops/:identifier/news/new(.:format) news#new
edit_shop_news GET /shops/:identifier/news/:id/edit(.:format) news#edit
shop_news GET /shops/:identifier/news/:id(.:format) news#show
PUT /shops/:identifier/news/:id(.:format) news#update
DELETE /shops/:identifier/news/:id(.:format) news#destroy
http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing
If you have those nike, adidas etc. in the database then the most straightforward option is to use match.
namespace :shop
match "/:shop_name" => "news#index"
match "/:shop_name/news" => "news#news"
end
However it seems to me that shop should be a resource for you. Just create a ShopsController (you don't need a matching model for it, just a controller). Then you can do
resources :shops, :path => "/shop"
resources :news
end
Now you can access the news index page (/shop/adidas) like this:
shop_path("adidas")
In the NewsController use :shop_id to access the name of the shop (yes even though it's _id it can be a string). Depending on your setup you may want news to be a singular resource, or the news method to be a collection method.
Also are you sure just renaming the news resource isn't something you want?
resources :news, :path => "/shop" do
get "news"
end
Keep in mind also that controller names and the number of controllers need not match your models. For example you can have a News model without a NewsController and a ShopsController without a Shop model. You might even consider adding a Shop model to your database if that makes sense.
In case this is not your setup then you might have oversimplified your example and you should provide a more full description of your setup.
I wanted to create a new action and I call it "showemployees". That's what I did already:
-> in the controller:
def showemployees
end
-> creating app/views/employees/showemployees.html.erb
-> in config/routes
match "/employees/showemployees" => "employees#showemployees"
I thought this is enough for opening the showemployees.html.erb now via localhost:3000/employees/showemployees , but it seems like Rails still routes through the show action (from resources :employees) and doesn't take the showemployees-action, because it tells me
ActiveRecord::RecordNotFound in EmployeesController#show
Couldn't find Employee with ID=showemployees
What do I need to change so Rails takes the showemployees-action?
the source code of my route:
System::Application.routes.draw do
match "/employees/showemployees" => "employees#showemployees" #für showemployees.html.erb
root :to => "employees#index"
resources :course_to_dos
resources :current_qualifications
resources :expected_qualifications
resources :skills
resources :employees
resources :positions
resources :admin
end
try to walk by Rails-way, if you want to get collection, use the collection
resources :employees do
collection do
get :showemployees
end
end
If you post your full routes file we can make a definitive call, but based on the error message, it looks like you have a broader route definition mapping to employees#show defined above this route in such a way that it is getting matched.
Routes are evaluated in the order they are defined, so if you have a very broad route pattern defined above a narrow one, your narrow route will never be called.
edit: you'll want to take the forward slash out of your route and add the showemployees to the actual URL, so that it reads
match "employees/showemployees" => "employees#showemployees"
I would like to map the following legacy url:
/:user_id/comments
comments is a resource, so in an idea world I would use something like:
resources :users, :prefix => nil do
resources :comments
end
Here I'm using prefix => nil but what I really want is to map just the user id. So instead of /users/:user_id/comments/ I have /:user_id/comments/.
Note that I'm not interested in declaring a users resource, so if there's something like a namespace that I can use instead all the better.
You can do a match statement to strip out the users folder:
match '/:user_id/:comments' => '/users/:user_id/:comments'
What I ended up using was:
scope ':user_id' do
resources :comments
end