Making a custom route - ruby-on-rails

The goal is to create a URL like this for a GET, REST API:
/manager/someID/report
example: /manager/2/report
I can get it to show in rake routes if do it this way:
get 'manager/:id/report', to: 'report#show'
But in some weblogs I read, thats the way unskilled developers write their routes! and looks like the better way is to use "nested resources" so I am banging my head over desk to get nested resources working the same way...but no success
this is what I have written so far:
resources :manager, only: [:show] do
resources :report, only: [:show], controller: 'report' do
member do
## WAT ?!
end
end
end

First, you might want to consider reading different blogs if they're calling routes like that "unskilled".
What you proposed is actually fine considering it's a non-standard RESTful route, and maybe even preferable in some cases. If you want an alternative approach, you have a couple different options. I don't think any one is more right than the other, but I prefer the first because it takes up less vertical space.
resources :manager, only: [:show] do
get 'report' => 'report#show', on: :member
end
or
resources :manager, only: [:show] do
member do
get 'report' => 'report#show'
end
end

Related

rails - Best practice for creating similar routes?

In my application, a User can make a Post, and a User can make Correction (think of it as a comment) on another user's post. Each User can have many Posts, and each Post can have many Corrections.
On each show page for a Post, there is a form to create a new Correction. This uses the user_post_corrections path.
On the show page for each User, I would like to display each Correction they've submitted for any Post. This requires a user_corrections path.
In order to achieve this, I have the following in my routes.rb:
resources :users do
resources :posts do
resources :corrections
end
end
resources :users do
resources :corrections
end
This intuitively feels bad to me, as I've created two nested routes that are very similar to one another.
Is there a better way to do this? My code is working fine as it is but is there a best practice method for implementing this kind of model?
Routing concerns are an excellent but underused tool for DRYing out your routes:
concern :correctable do
resources :corrections
end
# just an example of multiple concerns
concern :commentable do
resources :comments
end
resources :users, concerns: :correctable
resources :posts, concerns: [:correctable, :commentable]
However you should take when creating nested routes so that you are not nesting needlessly.
Often you might want the collective actions [new, index, create] to be scoped by the parent:
GET|POST /posts/:post_id/corrections
GET /posts/:post_id/corrections/new
While you want the member actions to be unscoped since you can always access a record directly if it has a unique id.
GET /corrections/:id
GET /corrections/:id/edit
PATCH /corrections/:id
DELETE /corrections/:id
To do this you would declare the routes like so:
resources :corrections, only: [:show, :update, :edit]
concern :correctable do
resources :corrections, only: [:new, :index, :create]
end
resources :users, :posts, concerns: [:correctable]
The shallow: true option does something like this but does not work well when you declare the same resources several times as it adds unscoped routes for every call.

Rails routes create resource but don't generate any on the 7 default actions

I have the following routes defined:
resources :users do
resources :suggestions do
post :make, on: :collection
end
end
I would like to tell resources :suggestions not to create any of the 7 default actions because I don't need them right now. With :only and :except I can limit the number of those actions being created, but I don't seem to figure how to create none of them.
Indeed, I could just leave the resources out and just define my :make route, but I would like to benefit from the automatic nesting and param handling, as well as leave a door open for a future need of several of the 7 default actions.
Hope this is helpful:-
resources :suggestions, only: [] do
end

Taking over an unused HTTP method of a resource

I have a restful Rails 4.2.1 controller with routes like so:
resources :users do
resources :labels, only: %w(index show update destroy)
end
Because this controller's model is incredibly tiny (just a name, an ID, and a couple associations that you wouldn't edit with this controller), I'd like to support mass-editing by PUTting or PATCHing the /users/:user_id/labels route. (PUT and PATCH are unused on the collection, and capture the semantic I'm trying to implement—that is, editing the whole collection.)
The problem is, I don't see how I can do that. I can say something like:
resources :users do
resources :labels, only: %w(index show update destroy) do
collection do
patch 'all', to: 'labels#update_many'
end
end
end
But that would result in a route of /users/:user_id/labels/all. Leaving the name string empty or nil seems to silently fail (rake routes doesn't show any indication of the route), and omitting it entirely causes an error. Meanwhile, doing something like this:
resources :users do
resources :labels, only: %w(index show update destroy)
member do
patch 'labels', to: 'labels#update_many'
end
end
Results in a route of /users/:id/labels, which is almost right except that the user ID comes in as :id instead of :user_id, which makes it difficult to handle fetching the user object.
I suppose I could hardcode the entire route in a root-level match command, but that just feels wrong.
Is there some trick I'm not aware of for doing this?
Try this:
resources :users do
resources :labels, only: %w(index show update destroy)
patch 'labels', to: 'labels#update_many'
end
The result route is:
PATCH /users/:user_id/labels(.:format) labels#update_many
This little trick also works:
resources :labels, only: %w(index update destroy) do
root to: 'labels#update_many', via: [:patch, :put], as: ''
end
When you do this, it wants to generate a redundant user_labels_root_path helper; the as: '' suppresses that.
However, Dabrorius's answer above is cleaner, so I'm going to use that one instead (modified to match both PATCH and PUT).

Mapping to the custom route

So far I have my routes like this: ( out of learning purposes I am curious to get it working with nested resources technique, but if you think this will get too complicated please feel free to suggest any other way of routing technique too)
resources :management, only: [:show] do
resources :report, only: [:show], controller: 'report' do
member do
# hmm what to write in here?!
end
end
end
my GOAL is to have a URL like this:
/managment/SOME_ID_WE_PASS_/report
/managment/1/report
But still can't figure out how exactly to write that route? Can you please take a look?
You don't need nested resources.
resources :crowd_management, only: [:show] do
get :exec_report, on: :member
end
That will produce:
/crowd_management/:id mapped to CrowdManagementController#show
/crowd_management/:id/exec_report mapped to CrowdManagementController#exec_report
The helper methods will be:
crowd_management_path
exec_report_crowd_management_path
You can run rake routes for a detailed list of all your routes.

Custom rails routing helper method

I am having issues getting my helper method names to work properly, any suggestions would be great:
#config/routes.rb
resources :junkie, only: [:show, :index, :destroy], as: :junkie do
get :merge, on: :collection
end
So I was having issues because I the singular form of junkies is junky, but when I make this change and look at the routes it changes the #merge helper to:
merge_junkie_index GET /junkies/merge(.:format) junkies#merge
Is there any way to change this to just merge_junkie? I tried removing it from the resource black and using the match syntax: get "junkies/merge" => "junkies#merge", as: :junkie but for some odd reason this directed me to the show method even though the route was right.
The solution is a ugly one but it works, since the show route is the only one that is affected by the as: :junkie you can break it out put the merge route in a separate block. The ordering of the resource also matters for some reason, if you do not put the merge first, it will interpret the url /junkie/merge/ as a id and hit the show action. So it should look like this in your routes file:
resources :junkies, only: [:index] do
get :merge, on: :collection
end
resources :junkies, only: [:show, :destroy], as: :junkie

Resources