Cleaner way to add routes to already defined resources :users - ruby-on-rails

My routes.rb has:
resources :users
Now if I add more routes in my users_controller, is there a way to bunch them together somehow instead of having a seperate line for each new route I add?
resources :users
# routes for signin, signout, password_recovery that are in users_controller
This is rails 3.

You can add routes that act on the collection or individual members with the member and collection block.
See the "Adding More RESTful Actions" section of the Rail's routing guide.

Related

Rails how to make example.com/post/1 to example.com/blog/post/1

I have a blog with root
root 'posts#index'
And works best with example.com/ to example.com/posts
But what I want is something like this:
example.com/blog/posts/1.
I've tried creating blog Controller and add
resources :blog do
resources :posts
end
But this is making my routes to blog/:id/posts/:id
If you don't have the relationship between the post and the blog as you mentioned, rails gives you the freedom to declare routes as our own.
so, to make the route example.com/posts/1 to, example.com/blog/posts/1, just add a custom route at the last.
get '/blog/posts/:id', to: :show, controller: 'posts'
what this does is over rides the previous route and make this route final.
Now type rake routes and it will give the last route for you as,
GET /blog/posts/:id(.:format) posts#show
Now you can access using,
example.com/blog/posts/1
Reference for rails routing
Just to expand upon #Sravan answer. If you have multiple routes that will start with /blog/ you might want to check Rails guide on routing.
You can add something along the lines of
scope '/blog' do
resources :posts
resources :users
resources :images
end
Which will create corresponding routes under /blog/.
namespace :blog do
resources :posts
resources :users
resources :images
end
And your controller with namespace will look like this: Blog::PostsController

Resource in and outside namespace

I have the following routes.rb:
resources :users
namespace :vmt do
resources :dashboards do
resources :users
resources :evaluation_units
resources :orga_units
end
end
I want to set the user in an overall context and nested in a single dashboard context within a namespace. The users-Controller is not in the namespace. So when I open the path /vmt/dashboards/1/users in browser, I get the following Routing Error
uninitialized constant Vmt::UsersController
So how can I specify, that in this resource
namespace :vmt do
resources :dashboards do
resources :users
that the controller is not in a namespace? I tried to set the controller explecitly with
resources :users, controller: 'user'
but it's still in the vmt namespace.
Using scopes will point rails to the proper url, but does not seem to provide the same useful route url helpers. We can, however, use / to point to the 'top level' controller.
Say you have two routes we want to display the users on:
/users and /admin/users
resources: users
namespace :admin do
resources :users, controller: '/users' # 'users' alone would look for a '/admin/users_controller'
end
With this, we can continue to use the url helper admin_users_path
(Note: Not a rails expert, there may be a way to create url helpers for scopes, or some other solution. Above tested on rails 5.2)
My original answer didn't work in the end, once you're inside a namespaced scope within a route you can't get out anymore.
The easiest way to re-use your logic is to create a Vmt::UsersController like so:
class Vmt::UsersController < ::UsersController
end
You can specify a different module with the module key.
For example:
resources :users, module: nil
Edit: I'm not 100% sure if this will work inside a namespace. If not, you can change it to a scope, and add the module explicitly to the other resources.

How to force custom Rails route to use :id instead of :<model>_id

I defined the following custom Rails route in routes.rb:
resources :projects do
get 'members'
end
This results in the following route (output from rake routes):
project_members GET /projects/:project_id/members(.:format)
What I would like, though, is for the route to map to this instead (change :project_id to :id)
project_members GET /projects/:id/members(.:format)
How can I make that happen?
Is members a nested resource? If so define it as one, and understand that this is why you have :project_id in the route, because :id in a nested resource is used by the final child item - you can't have multiple nested resources all using the same variable to define their id.
resources :projects do
resources :members
end
Add in a third level of nesting and it becomes a bit clearer to explain:
resources :projects do
resources :members do
resources :colours
end
end
With this nesting you could visit app/projects/:project_id/members/:member_id/colours/:id which would be served by the colours controller, which knows that :id defines an instance of that controllers model, and any other named id's belong to other resources.
Otherwise I think you just need to define it as a member method:
resources :projects do
member do
get 'members'
end
end
This tells the route that the action members is a non-resource action belonging to an instance of project, which I think should sort you out, but be sure it's the right thing to do.
See section 2.10 of Rails Routing from the Outside In

In RoR, do I have to specify every controller method as a route by hand?

What I'm wondering, in this case where I want to create a few web service type controllers, is if there is a way to "export" what method is allowed to be called from the controller. I'm still very new to RoR, and its routes feature, but in the end, is it expected that a fully functional RoR application just has hundreds of routes? Not every controller method I'm creating falls into a "resource" category.
Rails routes come in several varieties – RESTful routes are merely the ones that happen to provide native support for Rails resources. Remember that event resource routes can be modified to have member and collection routes:
# routes.rb
resources :products do
member do
get 'short' #=> products/:product_id/short/:id
post 'toggle' #=> products/:product_id/toggle/:id
end
collection do
get 'sold' #=> products/sold
end
end
You can also nest resource routes within other resource routes:
# routes.rb
resources :products do
resources :comments #=> RESTful routes patterned as products/:product_id/comments/:id/:action
resources :sales do
get 'recent', :on => :collection
end
end
Another handy feature is named routing. The following route is not resourceful:
# routes.rb
match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase # Creates route path akin to purchase_path(:id)
Namespaced routes can be very helpful for organization and readability:
# routes.rb
namespace :admin do
resources :products #=> RESTful routes patterned as admin/products/:product_id/:action
end
So, basically, there's a route for everything you want to do, whether it's RESTful/resourceful or not. But yes, you need to write a route for every action you want exposed to your app.
Using the routes.rb file, you can create routes or pattern matching for routes, as well as parameterized routes, and nested routes. You should read more about this here.
You can also give routes their own method name such as my_new_route_path. If you really wanted to, you could just hardcode routes into your HTML. Please don't do this.
Every controller action needs routes that map to it.

Custom actions in rails controller with restful actions?

I'm having some trouble with using creating my own actions inside a controller I generated using the scaffold.
I understand everything maps to the restful actions but I'm building a user controller where users can login/logout, etc but when I created the action and declared it in the routes.rb I get this error when I visit users/login
Couldn't find User with id=login
It tries to use login as a ID parameter instead of using it as an action.
Routes.rb
match 'users/login' => 'users#login'
I think I'm doing something wrong with the routes so if anybody could help me that would be great.
Thanks
I assume your routes.rb looks like this:
resources :users
match 'users/login' => 'users#login'
The problem is that Rails uses the first route that matches. From the documentation:
Rails routes are matched in the order they are specified, so if you have a resources :photos above a get 'photos/poll' the show action’s route for the resources line will be matched before the get line. To fix this, move the get line above the resources line so that it is matched first.
So either define your custom route before resources :users:
match 'users/login' => 'users#login'
resources :users
…or use this syntax for adding more RESTful actions:
resources :users do
collection do
match 'login'
end
end
To see the existing routes (and their order) run rake routes from the command line.

Resources