How to declare scope in Rails paths? - ruby-on-rails

I have an article resource that's defined as a flat resource, but also as one scoped to a variable user:
resources :articles
scope ':user' do
resources :articles
end
In this case, article_path 123 will generate /articles/123. How can I generate a scoped path, e.g. /mary/articles/123? For example, article_path 123, user: 'mary' doesn't work; it just adds ?user=mary.
rails routes shows there's no special name for the scoped path:
article_path GET /articles/:id(.:format) articles#show
...
GET /:user/articles(.:format) articles#index

Try adding, as to create route helpers
scope ':user', as: 'user' do
resources :articles
end
You will get
user_articles_path(user, article)
Check also routing

Related

Ruby on Rails - How to add a second route for the same action?

I have this route:
resources :posts do
resources :comments
end
A post can be a "User Message" showed at:
/posts
A post can be a "News" showed at:
/news
How can I create the "/news" url inside the routes.rb file and pass a param for know inside the post controller the type of post I want?
This way you can declare routes which can not be declared using resources.
get '/news' => 'posts#index', as: :news

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

Rails 4: routing error under a namespace

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.

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.

difference between collection route and member route in ruby on rails?

What is the difference between collection routes and member routes in Rails?
For example,
resources :photos do
member do
get :preview
end
end
versus
resources :photos do
collection do
get :search
end
end
I don't understand.
A member route will require an ID, because it acts on a member. A collection route doesn't because it acts on a collection of objects. Preview is an example of a member route, because it acts on (and displays) a single object. Search is an example of a collection route, because it acts on (and displays) a collection of objects.
URL Helper Description
----------------------------------------------------------------------------------------------------------------------------------
member /photos/1/preview preview_photo_path(photo) Acts on a specific resource so required id (preview specific photo)
collection /photos/search search_photos_path Acts on collection of resources(display all photos)
Theo's answer is correct. For documentation's sake, I'd like to also note that the two will generate different path helpers.
member {get 'preview'} will generate:
preview_photo_path(#photo) # /photos/1/preview
collection {get 'search'} will generate:
search_photos_path # /photos/search
Note plurality!
1) :collection - Add named routes for other actions that operate on the collection. Takes a hash of #{action} => #{method}, where method is :get/:post/:put/:delete, an array of any of the previous, or :any if the method does not matter. These routes map to a URL like /users/customers_list, with a route of customers_list_users_url.
map.resources :users, :collection => { :customers_list=> :get }
2) :member - Same as :collection, but for actions that operate on a
specific member.
map.resources :users, :member => { :inactive=> :post }
it treated as /users/1;inactive=> [:action => 'inactive', :id => 1]
Short Answer:
Both the member and collection blocks allow you to define additional routes for your resources than the seven standard routes that Rails will generate for you.
A member block creates new routes on a single member of the resource.
A collection block creates new routes for a collection of that resource.
Long Answer
Rails provides the member and collection blocks so you can define custom routes for both the resource collection and the individual resource.
Here's how you'd typically define routes for the article resource.
resources :articles
This creates the following routes.
➜ bin/rails routes -g article
Prefix Verb URI Pattern Controller#Action
articles GET /articles(.:format) articles#index
POST /articles(.:format) articles#create
new_article GET /articles/new(.:format) articles#new
edit_article GET /articles/:id/edit(.:format) articles#edit
article GET /articles/:id(.:format) articles#show
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
But let's say you are writing your articles in markdown, and need to see a preview of the article as you write it.
You could create a PreviewController and display the article's preview using its show action, but it's convenient to add a preview action on the ArticlesController itself.
Custom Member Routes
Here's how you define the preview route on the ArticlesController using the member block.
resources :articles do
member do
get 'preview'
end
end
It adds a new route that directs the request to ArticlesController#preview action. The remaining routes remain unchanged. It also passes the article id in params[:id] and creates the preview_article_path and preview_article_url helpers.
➜ bin/rails routes -g article
Prefix Verb URI Pattern Controller#Action
preview_article GET /articles/:id/preview(.:format) articles#preview
... remaining routes
If you have a single member route, use the short-hand version by passing the :on option to the route, eliminating the block.
resources :articles do
get 'preview', on: :member
end
You can go one step further and leave out the :on option.
resources :articles do
get 'preview'
end
It generates the following route.
➜ bin/rails routes -g preview
Prefix Verb URI Pattern Controller#Action
article_preview GET /articles/:article_id/preview(.:format) articles#preview
There are two important differences here:
The article's id is available as params[:article_id] instead of params[:id].
The route helpers changes from preview_article_path to article_preview_path and preview_article_url to article_preview_url.
Custom Collection Routes
To add a new route for the collection of a resource, use the collection block.
resources :articles do
collection do
get 'search'
end
end
This adds the following new route. It will also add a search_articles_path and search_articles_url helper.
search_articles GET /articles/search(.:format) articles#search
If you don't need multiple collection routes, just pass :on option to the route.
resources :articles do
get 'search', on: :collection
end
This will add the same route as above.
Conclusion
Rails allows you to break out of its convention of using seven resourceful routes using the member and collection blocks. Both allow you to define additional routes for your resources than the standard seven routes.
A member block acts on a single member of the resource, whereas a collection operates on a collection of that resource.
Source: Define New Routes Using the Member and Collection Blocks

Resources