Custom rails routing helper method - ruby-on-rails

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

Related

Issues with URL rewriting

I want to create an online system to read a magazine's pages, so I created two scaffolds (one for the magazine itself, the other, nested, for the pages). Everything is working fine, but the url appears like the following:
domain.com/magazines/<magazine title>/pages/2/
I tried make the URL look more like /<magazine title>/<page number> by simply removing the page's class name from the URL, which didn't work
Here is my router.rb file:
root to: 'home#index'
resources :magazines do
resources :pages, except: [:index, :edit, :new]
get '/:id' => 'pages#show', :as => 'custom'
end
But when I add a link_to "custom_path", I get undefined local variable or method 'custom_path' for #<#<Class:0x00000010bb1e70>:0x00000010bb0d18>
I know I did something wrong, but where?
Thank you in advance
Run rake routes so you can get the correct path names. Then again, if you want pages#show, it's already in resources list.

Is the order of the routes in the routes.rb important?

My routes.rb file looks like:
resources :contents, only: [:show]
get 'contents/by_hardware', to: 'contents#show_by_hardware'
With this setup I am not able to access the contents/by_hardware route.
But if I setup my routes.rb file in a different order, everthing works.
get 'contents/by_hardware', to: 'contents#show_by_hardware'
resources :contents, only: [:show]
Is the order in the routes.rb file important?
Yes, order matters very much.
It works like this: resources :contents, only: [:show] creates this route
content GET /contents/:id(.:format) contents#show
So when you request, for example, http://localhost:3000/contents/by_hardware, it is this route that matches this url. It invokes ContentsController#show action with params {'id' => "by_hardware"}. Your custom action is not considered, because matching route is already found.
Yes, order does matter. Instead of defining routes for the same controller at two different places, I would recommend you to define routes for the above scenario this way
resources :contents, only: [:show] do
get :show_by_hardware, on: :collection, path: :by_hardware
end
Hope that helps!
Yes it is important, the routes will be matched from top to bottom so you can move your route get 'contents/by_hardware', to: 'contents#show_by_hardware' above resource to fix your problem
yes. router will match first route from the top

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).

Why does this route setup result in these path variables?

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

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

Resources