Why does this route setup result in these path variables? - ruby-on-rails

In my rails 4 application, I have a piece in routes.rb that looks like this:
namespace :settings do
resources :profile, only: [:index] do
put :update_user, on: :collection
end
end
The controller is located in app/controllers/settings/profile_controller.rb and looks like this:
class Settings::ProfileController < ApplicationController
def index
end
def update_user
end
end
This results in these paths from rake routes:
PUT update_user_settings_profile_index -> /settings/profile/update_user(.:format)
GET settings_profile_index -> /settings/profile(.:format)
What I don't understand is why these paths have _index in them. I would like to get rid of it. Can I? If so, how?

I think that's because you're using a singular name profile for your resources definition, which should be plural by convention. You can try using resources :profiles instead.

For me, with routes it is always easier to work backwards, asking what are the paths I want? I'm not sure what paths you want, but I'll give you some ideas here, I hope.
I'm going to assume you want one index path, since you explicitly include the the only: [:index] statement, but you do not want not a indexed path on your resources.
Try moving your only: [:index] statement into the outer do loop for settings and add an only: [:update] to your profile (or whichever action you're looking for)
namespace :settings, only: [:index] do
resources :profile, only: [:update] do
put :update_user, on: :collection
end
end
Gets you here:
update_user_settings_profile_index PUT /settings/profile/update_user(.:format) settings/profile#update_user
settings_profile PATCH /settings/profile/:id(.:format) settings/profile#update
PUT /settings/profile/:id(.:format) settings/profile#update

Related

Rails 6 routes - proper way of simple nesting routes

Because it's been a while since I was using Rails monolith instead of GrapeAPI I've silly question. I want to create a route for path - users/portfolios/1/portfolio_reports/archived_reports where I will displays PortfolioReports.where(status: 'archived'). I created routes:
namespace :users do
resources :portfolios, only: [:index, :show] do
resources :archived_report, only: [:index, :show]
resources :portfolio_report, only: [:index, :show]
end
end
So I've got two questions: Should the routes file look like my current routes.rb ? and if I have Portfolio and PortfolioReport models like below, the portfolio_reports_controller should be inside app/controllers/users/portfolio_reports_controller.rb or app/controllers/portfolio_reports_controller.rb ?
class Portfolio
has_many :portfolio_reports
end
class PortfolioReport
belongs_to :portfolio
end
In Rails you can use "Shallow Nesting" which basically says to only nest the index, new and create actions under the parent resource. For the other actions you don't need to nest the routes, because through the record itself you have access to the associated record, so there is no need to have the id in the url.
So your routes will be:
users/portfolios/ # Portfolios#index
users/portfolios/1 # Portfolios#show
users/portfolios/1/portfolio_reports # PortfolioReports#index
users/portfolio_reports/1 # PortfolioReports#show
users/portfolios/1/archived_reports # ArchivedReports#index
users/archived_reports/1 # ArchivedReports#show
And routes.rb should look like this:
namespace :users do
resources :portfolios, only: [:index, :show] do
resources :archived_report, only: [:index]
resources :portfolio_report, only: [:index]
end
resources :archived_report, only: [:show]
resources :portfolio_report, only: [:show]
end
(If you'd use all 7 routes you could use the helper shallow as mentioned in the docs).
No need to nest archived_reports under portfolio_reports like you mentioned in your question!
Find more info on shallow nesting here: https://guides.rubyonrails.org/routing.html#shallow-nesting
For the user namespace:
Your controllers should live in a subfolder user because you have the namespace user:
app/controllers/user/portfolio_reports_controller.rb

How to properly add single route to existing route resources

I want to properly add new route to already existing route resources in Spree.
Desired end url format: /orders/:order_id/order_returns(.:format)
I can achieve this by adding following snippet to routes.rb:
Rails.application.routes.draw do
resources :orders, only: [] do
resources :order_returns, controller: 'order_returns', only: [:create]
end
end
but resources :orders, only: [] do looks kind of ugly with empty hash and if I remove it Rails will generate routes for orders :(
Is there a better, Rails/Spree way to achieve that ?

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.

Making a custom route

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

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