How to stop Rails route preempting another - ruby-on-rails

I am working on an API for a mobile app. I am running into a problem where one of my routes is preempting another. The two routes are:
api_vocabs_all GET /api/vocabs/all(.:format) api/vocabs#all
api_vocab GET /api/vocabs/:id(.:format) api/vocabs#show
Whenever I navigate to "api/vocabs/all" Rails sends the request to the show method with the id = all. Is there a way around this?
Update: Looking at my code again I noticed that while the above doesn't work the non-api version does work. Do I need to put my route inside the namespace?
vocabs_all GET /vocabs/all(.:format) vocabs#all
vocab GET /vocabs/:id(.:format) vocabs#show
Below are all my routes from routes.rb
namespace :api do
resources :vocabs
end
get 'vocabs/all' => 'vocabs#all'
get 'api/vocabs/all' => 'api/vocabs#all'
resources :vocabs

Converting my comment into an answer. Put api/vocabs/all above the namespace :api. Remember that your routing file should be ordered from most specific to least specific.
get 'api/vocabs/all' => 'api/vocabs#all'
namespace :api do
resources :vocabs
end
get 'vocabs/all' => 'vocabs#all'
resources :vocabs

Related

rename rails route

I have a route/path using CcpaAcknowledgmentsController
/ccpa_acknowledgments
I would like the route to be, BUT I would still like it to use the CcpaAcknowledgmentsController
/customers/ccpa_acknowledgments
Since I have these two routes...
resources :customers
resources :ccpa_acknowledgments
match '/customers/ccpa_acknowledgments', to: 'ccpa_acknowledgments#index', via: [:get]
I keep getting a conflict stating
NoMethodError in CustomersController.
Is there a way to get the desired route I want without putting the method/code in the CustomersController?
This is the way to do that
resources :customers do
get :ccpa_acknowledgments, to: 'ccpa_acknowledgments#index', on: :collection
end
Inside the customers block for two reasons:
we are fine with the beginning of the path /customers
we don't want to mess with the other customers' routes. In this way your route inside the block is before the customers default routes and it's not seen as you are calling customers/:id with ccpa_acknowledgments as id because rails takes care of that for you defining that route before the show
Then
get :ccpa_acknowledgments
because we need the second part of the path /ccpa_acknowledgments
to: 'ccpa_acknowledgments#index'
we want to specify the controller and action pair, because we want to use the CcpaAcknowledgmentsController even though we're inside the customers block
on: :collection
because we don't want any :id inside our route. It's a route defined on the customers collection
alternative using resources as asked in the comment. Try
scope :customers do
resources :ccpa_acknowledgments, only: :index
end
but you need to put this before the resources :customers

What's the "Rails way" to route a "diff" between two instances of the same model?

I'm building a "Brand personality" tool that gives you a report based on the text you share on social media.
I have a model PersonalityReport and in routes I have resources :personality_reports.
A new feature is to offer a "diff" between two reports and I'm trying to work out the most "guessable" way to model this in routes.
Ideally I'd like GET /personality_reports/:personality_report_id/diff/:id or something along those lines, and while I could simply put that into routes as a GET route, is there a more Railsy way of specifying a route using the resources / collections style so that my routes.rb file is more easy to understand?
The 'neatest' way can think of is:
resources :personality_reports, param: 'personality_report' do
member do
get 'diff/:id', to: 'personality_reports#action', as: 'diff_route'
end
end
Where obviously to: is your controller#action, and as: is the name of your route. After running rake routes you will see this generates:
diff_route_personality_report GET /personality_reports/:personality_report_id/diff/:id(.:format) personality_reports#action
I think whatever you mentioned is good enough,
resources : personality_reports do
resources :diffs, only: [:show]
end
So, routes like below,
personality_report_diff GET /personality_reports/:personality_report_id/diffs/:id(.:format) diffs#show
NOTE: You can also make diff route in singular resource :diff if you want to make it as singular resource.

Redirection in Rails 4 routes

My site used to have a mobile view here:
https://www.example.com/m/home
We have deprecated the mobile views and now I need a simple way to trim the /m/ off the URL so that the request proceeds to the correct page.
Example:
https://www.example.com/m/about => https://www.example.com/about
https://www.example.com/m/user/:id => https://www.example.com/user/:id
I'm hoping to solve this in the Rails routing without having to introduce a new controller action or meddle with nginx. I have 100+ routes. Thanks in advance.
Rails version: 4.2
There is a redirection module (also documented in the guide).
Something like :
get '/m/about', to: redirect('/about')
get '/m/user/:id', to: redirect('/user/%{id}')
Which you can combine with route globbing for a generic solution :
get '/m/*path', to: redirect('/%{path}')
How about just refactor your routes a bit:
Eg: Previous routes.rb
resources :users
# ...
Now, it becomes:
['m', ''].each do |sc|
scope sc do
resources :users
# ...
end
end

Getting no route matches on the show action

I'm trying to use the path from the following route, here is what it's like in rake routes
chapter GET /chapters/:id(.:format) {:action=>"show", :controller=>"chapters"}
chapter_path creates a link to /chapters/x which is correct but I get the routing error when trying to access it.
No route matches {:controller=>"chapters"}`
this is my routes (I am using shallow routing to create a books_chapters and book_chapters_new paths.
resources :books do
resources :chapters, :shallow => true
end
when I test the route with rake routes, I get books_chapters, books_chapters_new, chapters and books, so I don't know what's wrong.
when i remove :shallow => true, i can access /books/1/chapters/6 but I just want it to be /chapters/6
this is what my terminal looks like
so /chapters/id and /chapters/id/edit should be working fine.
I've restarted the server with touch tmp/restart.txt and ran rails s to see if the routes worked there too and rake routes is giving me acceptable routes, but they don't work for me.
Are you supplying the parameter for the path helper, something like
chapter_path(#chapter)
I couldn't figure out how to get :shallow routes to work, and there isn't an example on how to use :shallow in the rails guide so, instead I have to just use nested routes like so
resources :books do
resources :chapters
end
now this means the something like chapters_url or chapters_path won't work.
So I have to do something like this everywhere
book_chapter_url(#chapter.book, #chapter)
or
edit_book_chapter_path(#chapter.book, #chapter)
It works but there's a bit of code smell because I use #chapter twice and the whole url should be able to resolve just through the chapter id instead.

How to remove controller name in REST design in Rails3?

Given a User resource, it goes like this
/user/:shortname
But how can the controller name be removed to get just
/:shortname
How can I declare this in routes.rb while keeping all CRUD functionality instant?
Updated: After reading this I'm moving to Sinatra over Rails to handle this API-like design better.
Define a custom match:
match ':shortname' => 'users#action'
Replace action in users#action with the name of the action that is supposed to receive the request. Just remember to place it in the appropriate order in your routes file. Rails looks at each line of your routes file starting at the top and selects the first matching route. ':shortname' would match any first-level path, including /users! So put it below any routes using a first-level path, which would include all of your resource routes. Here's an example:
resources :users
resources :posts
match '/blog' => 'posts#index'
match ':shortname' => 'users#action'
In routes, you should be able to do something like
resource :users, :path => '/:shortname'
Try that out and rake routes to see if that comes out as expected.

Resources