Rails 3.1 has_one nested resource: routing not generating "all" paths - ruby-on-rails

I have a has_one relation:
# supplier.rb
has_one :presentation
...
# presentation.rb
belongs_to :supplier
...
and the folowing nested routes for them:
# routes.rb
resources :suppliers do
resource :presentation
end
running rake routesgives:
supplier_presentation POST ... {:action=>"create", :controller=>"presentations"}
new_supplier_presentation GET ... {:action=>"new", :controller=>"presentations"}
edit_supplier_presentation GET ... {:action=>"edit", :controller=>"presentations"}
GET ... {:action=>"show", :controller=>"presentations"}
PUT ... {:action=>"update", :controller=>"presentations"}
DELETE ... {:action=>"destroy", :controller=>"presentations"}
Why no name_helper for the show action?
I can override the problem doing something like:
resources :suppliers do
resource :presentation, :except => :show do
get "" => "presentations#show", as: "presentation"
end
end
giving the route:
presentation_supplier_presentation GET ... {:controller=>"presentations", :action=>"show"}
but we all now that's not the right way to deal with it..
ANY SUGGESTIONS?
--
(edited)
supplier_presentation_path(#supplier)
does work, but why?... It doesn't appear when rake routes is executed on my shell...

I dont really know why it's not displayed when you do rake routes but did you try in your code to do supplier_presentation_path(#supplier)? It should work based on your routes.

Never the less it should work for you. Try this:
link_to "Presentation", [#suplier, #presentation]
or
link_to "Presentation", suplier_presentation_path(#suplier, #presentation)

Related

Routes on Rails application are failing

I'm taking an MOOC and the goal of this exercise is to add a new functionality to typo, where i can merge two articles together.
When I add the route to my new function merge to the routes.rb I'm losing the functionality to delete articles. I think something clashes here, but I have no idea what.
The original routes.rb:
%w{advanced cache categories comments content profiles feedback general pages
resources sidebar textfilters themes trackbacks users settings tags redirects seo post_types }.each do |i|
match "/admin/#{i}", :to => "admin/#{i}#index", :format => false
match "/admin/#{i}(/:action(/:id))", :to => "admin/#{i}", :action => nil, :id => nil, :format => false
end
This method in articles.rb creates the correct url for deleting
def delete_url
blog.url_for(:controller => "/admin/content", :action =>"destroy",:id => id)
end
correct url:
http://example.com/admin/content/destroy/7
If i follow this link i can successfully delete an article.
However, if I add the following before that to my routes.rb:
namespace "admin" do
resources :content do
post :merge, on: :member, as: :merge
end
end
The new merging functionality and forms are working fine, but the method delete_url now produces something like this:
http://example.com/admin/content/7
and if I follow a link created by this method i get:
Unknown action
The action 'show' could not be found for Admin::ContentController
Maybe I'm overwriting something? I can't figure out what's happening here and why this affects the delete action / route.
Thanks in advance!
EDIT: rake routes | grep content:
with the original routes.rb gives me:
admin_content /admin/content {:controller=>"admin/content", :action=>"index"}
/admin/content(/:action(/:id)) {:action=>nil, :id=>nil, :controller=>"admin/content"}
whereas my modified routes.rb produces
merge_admin_content POST /admin/content/:id/merge(.:format) {:action=>"merge", :controller=>"admin/content"}
admin_content_index GET /admin/content(.:format) {:action=>"index", :controller=>"admin/content"}
POST /admin/content(.:format) {:action=>"create", :controller=>"admin/content"}
new_admin_content GET /admin/content/new(.:format) {:action=>"new", :controller=>"admin/content"}
edit_admin_content GET /admin/content/:id/edit(.:format) {:action=>"edit", :controller=>"admin/content"}
admin_content GET /admin/content/:id(.:format) {:action=>"show", :controller=>"admin/content"}
PUT /admin/content/:id(.:format) {:action=>"update", :controller=>"admin/content"}
DELETE /admin/content/:id(.:format) {:action=>"destroy", :controller=>"admin/content"}
/admin/content {:controller=>"admin/content", :action=>"index"}
/admin/content(/:action(/:id)) {:action=>nil, :id=>nil, :controller=>"admin/content"}
Okay, thanks to #guitarman i worked through my routes code and found out I can add the following except:
namespace "admin" do
resources :content, except: [:index, :show, :update, :destroy, :edit, :new, :create] do
post :merge, on: :member, as: :merge
end
end
after that, the rake routes just shows the additional merge route I wanted and my destroy action works fine again.
Check rake routes command. I think there is a route /admin/content/:id which will be created by resources :content in the namespace "admin".
Your request to http://example.com/admin/content/7 will be catched be the defined route but I gess you have no show action in the controller.
Better:
namespace "admin" do
post "/content/:id/merge", to: "admin/content#merge", as: :merge
end
For more information about recources and the CRUD operations please see the rails routing guide.

Rails member routing, should be easy?

For this route:
resources :projects do
member do
resources :stakeholders
end
end
The generated routes are:
projects_stakeholders GET /projects/projects/:id/stakeholders(.:format) {:action=>"index", :controller=>"projects/stakeholders"}
POST /projects/projects/:id/stakeholders(.:format) {:action=>"create", :controller=>"projects/stakeholders"}
new_projects_stakeholder GET /projects/projects/:id/stakeholders/new(.:format) {:action=>"new", :controller=>"projects/stakeholders"}
edit_projects_stakeholder GET /projects/projects/:id/stakeholders/:id/edit(.:format) {:action=>"edit", :controller=>"projects/stakeholders"}
projects_stakeholder GET /projects/projects/:id/stakeholders/:id(.:format) {:action=>"show", :controller=>"projects/stakeholders"}
As these routes have two times a :id parameter, if I have, for instance the URL 'projects/4/stakeholders/11'
In my log file I see this:
Parameters: {"id"=>"11"}
How can I then access my project_id from inside my controller?
Thanks!!!
You don't need the member do block around it. Just do this, and you should start seeing a project_id in your params:
resources :projects do
resources :stakeholders
end

route index for a resource

What is the equivalent index path for resources :topics if I were to write it out manually?
When I run rake routes with the resources line in the routes.rb file it shows.
GET /topics(.:format) {:action=>"index", :controller=>"topics"}
I have tried a few things with no success, for example:
get 'topics/index' #=> 'topics#index'
as the route says:
get "/topics" => "topics#index", :as => :topics
you can now use topics_path or topics_url

Testing nested resources with RSpec

I am trying to create tests for nested resources in Rails. The relevant route definition is:
resources :communities do
resources :contents, :type => 'Content'
end
Using RSpec and factory_girl, I am trying to get started with testing with e.g.
describe ContentsController do
it 'should display a content item under a community' do
content = FactoryGirl.create(:content)
get :show, :community_id => content.community.id, :id => content.id
end
end
These requests always result in
Failure/Error: get :show, :community_id => content.community.id, :id => content.id
ActionController::RoutingError:
No route matches {:community_id=>BSON::ObjectId('4e7773c6ac54c3d1ad000002'),
:id=>BSON::ObjectId('4e7773c6ac54c3d1ad000001'), :controller=>"contents",
:action=>"show"}
For the life of me I cannot find a way to specify a route to a nested resource with RSpec. Am I doing something fundamentally wrong here?
Update: The relevant part of rake routes is:
community_contents GET /communities/:community_id/contents(.:format) {:action=>"index", :controller=>"contents"}
POST /communities/:community_id/contents(.:format) {:action=>"create", :controller=>"contents"}
new_community_content GET /communities/:community_id/contents/new(.:format) {:action=>"new", :controller=>"contents"}
edit_community_content GET /communities/:community_id/contents/:id/edit(.:format) {:action=>"edit", :controller=>"contents"}
community_content GET /communities/:community_id/contents/:id(.:format) {:action=>"show", :controller=>"contents"}
PUT /communities/:community_id/contents/:id(.:format) {:action=>"update", :controller=>"contents"}
DELETE /communities/:community_id/contents/:id(.:format) {:action=>"destroy", :controller=>"contents"}
I see that you are passing the content.community.id as the :community_id and that object looks like a mongo document that is identified with a BSON::ObjectId. Try to use to_param instead as following:
get :show, :community_id => content.community.to_param, :id => content.to_param

No Route Matches error - with Nested Resource

I have the following Nested Resource in my routes.rb file
resource :issuer do
resources :certificates
end
My Models:
class Issuer < ActiveRecord::Base
has_many :certificates
end
class Certificate < ActiveRecord::Base
belongs_to :issuer
end
I get the following error when i visit: /issuer/2/certificates
No route matches {:action=>"edit", :controller=>"certificates"}
Any help would be appreciated.. Thanks in advance!
EDIT : MY rake routes
issuer_certificates GET /issuer/:issuer_id/certificates(.:format) {:action=>"index", :controller=>"certificates"}
POST /issuer/:issuer_id/certificates(.:format) {:action=>"create", :controller=>"certificates"}
new_issuer_certificate GET /issuer/:issuer_id/certificates/new(.:format) {:action=>"new", :controller=>"certificates"}
edit_issuer_certificate GET /issuer/:issuer_id/certificates/:id/edit(.:format) {:action=>"edit", :controller=>"certificates"}
issuer_certificate GET /issuer/:issuer_id/certificates/:id(.:format) {:action=>"show", :controller=>"certificates"}
PUT /issuer/:issuer_id/certificates/:id(.:format) {:action=>"update", :controller=>"certificates"}
DELETE /issuer/:issuer_id/certificates/:id(.:format) {:action=>"destroy", :controller=>"certificates"}
You should use resources (plural) instead of resource in refer to :issuer. So please try this:
resources :issuers do
resources :certificates
end
and issuers/2/certificates will work.
In your routes.rb file you are defining issuer as a singular resource
resource :issuer do # <----- using resource instead of resources
resources :certificates
end
With singular resources, the routes you get won't allow an :id to be matched, so in your example,
issuer/2/certificates
it's the "2" that's giving you grief. You should either get rid of it or define :issuer as a standard (non-singular) resource in your routes.rb file.
You don't have PUT defined for /issuer/2/certificates. instead you have it defined for /issuer/2/certificates/123. That's why you get that error.
If you are trying to edit the certificate then make sure you generate a correct link and include certificate_id.

Resources