Rails 4: routing error under a namespace - ruby-on-rails

In routes.rb:
namespace :account do
resource :groups
resource :posts
end
But I got error when located http://0.0.0.0:3000/account/groups :
***Unknown action
The action 'show' could not be found for Account::GroupsController***
I checked http://0.0.0.0:3000/rails/info/routes and got:
```
account_groups_path POST /account/groups(.:format) account/groups#create
new_account_groups_path GET /account/groups/new(.:format) account/groups#new
edit_account_groups_path GET /account/groups/edit(.:format) account/groups#edit
GET /account/groups(.:format) account/groups#show
PATCH /account/groups(.:format) account/groups#update
PUT /account/groups(.:format) account/groups#update
DELETE /account/groups(.:format) account/groups#destroy
```
Why account/groups not map to index method?

If you'd like to generate only index action then update your route file to restrict the routes created to just index as follows:
namespace :account do
resource :groups, only: [ :index ]
resource :posts
end
The problem however is your resource declaration, you're using singular resource, i.e. resource :groups and resource :posts. What this does is map /account/groups to account/groups#show and account/posts#show. Pluralizing resource will be a better solution:
namespace :account do
resources :groups
resources :posts
end
With this change, running rake routes should provide you the index action you are looking for.

Related

Ruby on Rails No route matches [POST]

I'm attempting to maintain some legacy code but I'm struggling to figure out why my defined route isn't working.
The error I'm getting is
Started POST "/api/transactions/weight" ...
ActionController::RoutingError (No route matches [POST] "/api/transactions/weight"):
My (simplified) route is as follows
namespace :api do
resources :transactions, only: [:create] do
post "weight", to: "transactions#weight"
end
end
I've also tried moving the route outside the resource :transactions definition like so
namespace :api do
resources :transactions, only: [:create]
post "transactions/weight", to: "transactions#weight"
end
But I'm getting the same error. Am I misunderstanding route definition, or is the problem elsewhere? Thanks
Always check bundle exec rake routes to understand your routes.
The post method defines "/weight" route as a member route (acting on a specific "transactions" resource
# bundle exec rake routes
api_transaction_weight POST /api/transactions/:transaction_id/weight(.:format). api/transactions#weight
By default, if you don't specify on: option, the route inside resources block gets created as member route.
You want to specify it as a collection route [1] via on: :collection
namespace :api do
resources :transactions, only: [:create] do
post "weight", to: "transactions#weight", on: :collection
end
end
# bundle exec rake routes
weight_api_transactions POST /api/transactions/weight(.:format) api/transactions#weight
[1] https://guides.rubyonrails.org/routing.html#adding-collection-routes
The way you defined routes will consider "weight" as the member route. If you want to define it as collection route.
namespace :api do
resources :transactions, only: [:create] do
collection {post :weight}
end
end
The above convention will expose weight as collection route and not member route.If you want to be defined as member post request. Then use following convention
namespace :api do
resources :transactions, only: [:create] do
member {post :weight}
end
end
If you are using api.rb as draw file in routes, then you need to restart your application to reflect changes in routes file.

Define specific route to nested resources

I've been trying rails and I found myself with a very simple problem: I have two models, survivors and locations, and they're nested resources in routes.rb
Rails.application.routes.draw do
namespace 'api' do
namespace 'v1' do
resources :survivors do
resources :locations
end
resources :abduction_reports
end
end
end
which gives me almost all the routes I need. The problem is that survivors and locations is one-to-one association, so if I want to update the survivor location, it seems more interesting if the end-point for that is
PUT /survivors/:survivor_id/location
To solve it, I did this:
Rails.application.routes.draw do
namespace 'api' do
namespace 'v1' do
[...]
put 'survivors/:survivor_id/location', to: 'locations#update'
end
end
end
but it doesn't seem the correct way to do it... I mean, can it be defined inside the 'resources :survivors do ... end' scope?
I probably have already seen it in the rails documentation, but I think I just haven't realized how to adapt the documentation examples to my problem yet.
For a singular resource use the resource macro instead:
Rails.application.routes.draw do
namespace 'api' do
namespace 'v1' do
resources :survivors do
resource :location
end
resources :abduction_reports
end
end
end
Prefix Verb URI Pattern Controller#Action
api_v1_survivor_location POST /api/v1/survivors/:survivor_id/location(.:format) api/v1/locations#create
new_api_v1_survivor_location GET /api/v1/survivors/:survivor_id/location/new(.:format) api/v1/locations#new
edit_api_v1_survivor_location GET /api/v1/survivors/:survivor_id/location/edit(.:format) api/v1/locations#edit
GET /api/v1/survivors/:survivor_id/location(.:format) api/v1/locations#show
PATCH /api/v1/survivors/:survivor_id/location(.:format) api/v1/locations#update
PUT /api/v1/survivors/:survivor_id/location(.:format) api/v1/locations#update
DELETE /api/v1/survivors/:survivor_id/location(.:format) api/v1/locations#destroy
api_v1_survivors GET /api/v1/survivors(.:format) api/v1/survivors#index
POST /api/v1/survivors(.:format) api/v1/survivors#create
new_api_v1_survivor GET /api/v1/survivors/new(.:format) api/v1/survivors#new
edit_api_v1_survivor GET /api/v1/survivors/:id/edit(.:format) api/v1/survivors#edit
api_v1_survivor GET /api/v1/survivors/:id(.:format) api/v1/survivors#show
PATCH /api/v1/survivors/:id(.:format) api/v1/survivors#update
PUT /api/v1/survivors/:id(.:format) api/v1/survivors#update
DELETE /api/v1/survivors/:id(.:format) api/v1/survivors#destroy
See:
https://guides.rubyonrails.org/routing.html#singular-resources

No route matches [PUT], resource and method are defined though

I'm using postman to make a PUT or PATCH request, but it says No route matches [PUT] "/api/registrations"
my URL looks like this
http://localhost:3000/api/registrations?id=5&status=approved"
My routes.rb file:
Rails.application.routes.draw do
scope :api do
resources :professors
resources :registrations
resources :schedules
resources :notifications
resources :users
resources :meetings
resources :courses
resources :students
end
end
I have a defined update method in my RegistrationsController and My POST and GET routes work.
The URL you're using is incorrent. You should not pass id in query, but in path.
A correct URL is
http://localhost:3000/api/registrations/5?status=approved
Rails sets id as last element of a resourceful route.
Docs say:
resources :photos
(...)
PATCH/PUT /photos/:id photos#update update a specific photo
Run rails routes on the command line to get the proper URL pattern and it's matching Controller action.

Rails routes index for nested resource

I'm searching a reason why rake routes doesn't match the index path of my nested resource.
Here is my code:
namespace :api do
resources :photos do
resource :comments
end
end
Here is the result of the command: rake routes | grep comment
batch_action_admin_user_comments POST /admin/user_comments/batch_action(.:format) admin/user_comments#batch_action
admin_user_comments GET /admin/user_comments(.:format) admin/user_comments#index
POST /admin/user_comments(.:format) admin/user_comments#create
new_admin_user_comment GET /admin/user_comments/new(.:format) admin/user_comments#new
edit_admin_user_comment GET /admin/user_comments/:id/edit(.:format) admin/user_comments#edit
admin_user_comment GET /admin/user_comments/:id(.:format) admin/user_comments#show
PATCH /admin/user_comments/:id(.:format) admin/user_comments#update
PUT /admin/user_comments/:id(.:format) admin/user_comments#update
DELETE /admin/user_comments/:id(.:format) admin/user_comments#destroy
admin_comments GET /admin/comments(.:format) admin/comments#index
POST /admin/comments(.:format) admin/comments#create
admin_comment GET /admin/comments/:id(.:format) admin/comments#show
api_photo_comments POST /api/photos/:photo_id/comments(.:format) api/comments#create
new_api_photo_comments GET /api/photos/:photo_id/comments/new(.:format) api/comments#new
edit_api_photo_comments GET /api/photos/:photo_id/comments/edit(.:format) api/comments#edit
GET /api/photos/:photo_id/comments(.:format) api/comments#show
PATCH /api/photos/:photo_id/comments(.:format) api/comments#update
PUT /api/photos/:photo_id/comments(.:format) api/comments#update
DELETE /api/photos/:photo_id/comments(.:format) api/comments#destroy
I tried to add only: [:create, :index] to my comments resource but only the create route is visible.
According to the documentation about nested-resources I don't understand what's happening.
Thank you for your help.
It's because you are using a singular resource (resource :comments)
From the docs:
Sometimes, you have a resource that clients always look up without
referencing an ID. For example, you would like /profile to always show
the profile of the currently logged in user. In this case, you can use
a singular resource to map /profile (rather than /profile/:id) to the
show action
You'll need to use the standard resources method to get this working (resource omits the index action):
#config/routes.rb
namespace :api do
resources :photos do
resources :comments
end
end
My mistake. A "S" was missing on my resource.
namespace :api do
resources :photos do
resources :comments
end
end
Now it works.

Routing Error: uninitialized constant

I'm trying to set up routes for a mobile API, which should have a versioned api-path. I already could make the mobile Auth work, which is implemented in a separate Controller AuthController located in /controllers/api/v1/mobile/.
Usage example:
myapp.com/api/v1/mobile/auth
But now I want to register my existing ressources-Controllers to this path-pattern as additional api-routes. Concrete: this would be the TasksController located at /controllers/tracker/tasks_controller.rb. So I added a mobile route to the routes-definition:
# routes.rb
namespace :tracker, path: 'timetracking' do
resources :tasks, 'jobs'
end
namespace :api do
namespace :v1 do
namespace :mobile do
resources :auth, :only => [:create, :destroy]
namespace :tracker do #added mobile route
resource :tasks, controller: 'tracker/tasks', as: :mobile_tasks
end
end
end
end
But when I call myapp.com/api/v1/mobile/tracker/tasks it results in an error-message:
Routing Error
uninitialized constant Api::V1::Mobile::Tracker
I especially added the alias :mobile_tasks to this route, to avoid any conflicts with the original tasks-route above. Any ideas, how to set the controller properly for this route?
Update#1
Defining this route as a scope instead of a namespace, didn't work aswell.
scope "/api/v1/mobile/tracker" do
resources :tasks, controller: 'tracker/tasks', as: :mobile_tasks
end
But this time, it didn't even resolve the route-path itself.
Routing Error
No route matches [GET] "/api/v1/mobile/tracker/tasks"
I assume it might be a problem, that my additional mobile-api route tries to point to a completely different namespace tracker.
According to http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing you should use scope instead of namespace.
If you want to route /admin/posts to PostsController (without the Admin:: module prefix), you could use:
scope "/admin" do
resources :posts, :comments
end
Adding this answer to get clarity on namespace & scope.
When you use namespace, it will prefix the URL path for the specified resources, and try to locate the controller under a module named in the same manner as the namespace.
# config/routes.rb
namespace :admin do
resources :posts, only: [:index]
end
# rake routes
Prefix Verb URI Pattern Controller#Action
admin_posts GET /admin/posts(.:format) admin/posts#index
When we add scope, it will just map the controller action for the given scope patterns. No need to define controller under any module.
# config/routes.rb
scope :admin do
resources :posts, only: [:index]
end
# rake routes
Prefix Verb URI Pattern Controller#Action
admin_posts GET /admin/posts(.:format) posts#index
Note that, controller is just posts controller without any module namespace.
If we add a path option to scope it will map to the controller with the path option specified as follows
# config/routes.rb
scope module: 'admin', path: 'admin' do
resources :posts, only: [:index]
end
# rake routes
Prefix Verb URI Pattern Controller#Action
admin_posts GET /admin/posts(.:format) admin/posts#index
Note that the controller now is under admin module.
Now, if we want to change the name of path method to identify resource, we can add as option to scope.
# config/routes.rb
namespace module: 'admin', path: 'admin', as: 'root' do
resources :posts, only: [:index]
end
# rake routes
Prefix Verb URI Pattern Controller#Action
root_posts GET /admin/posts(.:format) admin/posts#index
You can see the change in the Prefix Verb.
Hope it helps others.
Late answer, but still might be helpful:
scope '/v1' do
resources :articles, module: 'v1'
end
controller
# app/controller/v1/articles_controller.rb
class V1::ArticlesController < ApplicationController
end
Now you should be able to access this url:
http://localhost:3000/v1/articles

Resources