rails passing in id parameter ambiguous - ruby-on-rails

If I have a route:
/users/9/follow
"9" comes in like this:
Parameters: {"id"=>"9"}
But if I have a route:
/images/6936/like
then parameter has image appended to it:
Parameters: {"image_id"=>"6936"}
Just wondering how I should know if it's id or resourcename_id.

Extract from Rails Routing from the Outside In
2.10.1 Adding Member Routes
To add a member route, just add a member block into the resource
block:
resources :photos do
member do
get 'preview'
end
end
This will recognize /photos/1/preview with GET, and route to
the preview action of PhotosController, with the resource id value
passed in params[:id]. It will also create the preview_photo_url
and preview_photo_path helpers.
Within the block of member routes, each route name specifies the HTTP
verb that it will recognize. You can use get, patch, put, post, or
delete here. If you don't have multiple member routes, you can also
pass :on to a route, eliminating the block:
resources :photos do
get 'preview', on: :member
end
And the actual answer to your question is in the last paragraph:
You can leave out the :on option, this will create the same member
route except that the resource id value will be available in
params[:photo_id] instead of params[:id].

Related

Rails: Difference between declaring a route directly inside the `resources` block vs. enclosing it with a `member` block

What's the difference between the /animals/:animal_id/info(.:format) and /animals/:id/info(.:format) routes in the following, except parameter names? And why are the parameter names different?
config/routes.rb
Rails.application.routes.draw do
resources :animals do
get 'info'
member do
get 'info'
end
end
end
~/myrails>rails routes
Prefix Verb URI Pattern Controller#Action
animal_info GET /animals/:animal_id/info(.:format) animals#info
info_animal GET /animals/:id/info(.:format) animals#info
First of all, if we write the member block or directly write the get routes inside the resources both are considered as member routes.
Its the rails convention to differentiate between both of the routes. If we write the member block it is considered that all the routes declared within that block are declared from the member block explicitly.
resources :animals do
member do
get 'info'
end
end
info_animal GET /animals/:id/info(.:format) animals#info
But if we directly declare get or other routes inside the resources block this will also create the same member route except that the resource id value will be available in params[:animal_id] instead of params[:id]. Route helpers will also be renamed from info_animal_url and info_animal_path to animal_info_url and animal_info_path. I think this is to make difference that request is not coming from the member block.
resources :animals do
get 'info'
end
animal_info GET /animals/:animal_id/info(.:format) animals#info
If we write get route with the on: option with value :member inside the resources directly then this will be treated same as the member block route
resources :animals do
get 'info', on: :member
end
info_animal GET /animals/:id/info(.:format) animals#info

Rails 5: How to overwrite route parameters for extra member route

In Rails 5 I've figured out how to
Overwrite the route parameter from id to something like name
Add another route for a resource
So that my routes.rb looks something like this
Rails.application.routes.draw do
resources :cats, param: :name
resources :cats do
get :preview, on: :member
end
end
I've noticed however that my additional preview route does not keep the overwritten named route parameter. Instead, when looking at the output from rake routes, I have something that looks like this.
GET /cats/:id/preview(.:format)
when what I was expecting, and trying to achieve, was a route that looks like
GET /cats/:name/preview(.:format)
How do I both add an additional route to a resource while overwriting the parameter?
You're duplicating your routes entries for cats, and you've provided the block for declaring the preview route on the entry missing the param name override. You need to provide the override and the block in the same route declaration.
Rails.application.routes.draw do
resources :cats, param: :name do
get :preview, on: :member
end
end
This gives you the route you want:
$ rake routes
Prefix Verb URI Pattern Controller#Action
preview_cat GET /cats/:name/preview(.:format) cats#preview

when does rails looks for Index method and when for show method in controller

I'm new to Rails and I have been following a tutorial.
I have been fiddling around with routes.rb and now in total confusion about when it looks for show method and when for index method if not explicitly mentioned?
Routes are simply like regexes on steroids. They have priority in the order they are defined and match the request method, URI and any other constraints that you have added.
get '/posts', to: 'posts#index'
get '/posts/:id', to: 'posts#show'
The key difference to the routes above is that the regular expression which the path of request uri must match is different. '/posts/:id' includes a named segment which would match:
GET /posts/11
GET /posts/gobligook
But not:
GET /posts
GET /posts/1/foo
GET /posts/foo/bar
The full conventional set of CRUD verbs are:
get '/posts', to: 'posts#index' # all posts
get '/posts/new', to: 'posts#new' # form to create a post
post '/posts', to: 'posts#create' # create a post from a form submission
get '/posts/:id', to: 'posts#show' # show a single post
get '/posts/:id/edit', to: 'posts#edit' # form to edit a post
put '/posts/:id', to: 'posts#update' # for legacy compatibility
patch '/posts/:id', to: 'posts#update' # update a post from a form submission
delete '/posts/:id', to: 'posts#destroy' # delete a post
In Rails flavor REST the action is implicitly derived from the path and method.
Only the new and edit methods which are used to render forms actually explicitly add the action in the path - which is because they act on a collection or a member of a collection.
Note that the '/posts/new' route must be declared before get '/posts/:id' or the show route would match the request first (routes have priority in the order they are defined). This does not apply to get '/posts/:id/edit' since the pattern is different.
Of course typing out all those routes is really tedious so rails provides the resources macro that does this for you:
resources :posts
Both index and show are GET method, but the difference is index is collection type and show is member type. Which means index does not expect any parameter in the url, but show expects id param in the url.
EX:
Index: /posts
Show: /posts/:id
Rails chose convention over configuration. That's why the actions are not explicitly named.
Here is the complete list of the expected actions for a given controller: http://edgeguides.rubyonrails.org/routing.html#crud-verbs-and-actions

How to remove the prefix generated in routes.rb for the params in the path

Currently in my routes I have:
# USER RESOURCES
resources :users do
resources :repositories
patch 'change_password'
get 'account_setting'
end
Which generates this path for the account_setting action:
user_account_setting GET /users/:user_id/account_setting(.:format) users#account_setting
What I want is to have:
user_account_setting GET /users/:id/account_setting(.:format) users#account_setting
The two are essentially the same thing, but the first has a user_ prefix for the id which rails adds because it is in users resource block.
SIDE NOTE
I know I can simply remove the account_setting action from the users resource block and write:
get 'users/:id/account_setting', to: 'users#account_setting'
But I don't want to.
You can do it as follows:
resources :users do
member do
get 'account_setting'
end
end
To add a member route, add a member block into the resource block.
For documentation, you can check http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Resources.html

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