Aliasing routes in rails 4 - ruby-on-rails

If I have the following routes
resources :pages do
resources :sections
end
I get routes that look like this:
/pages = #index
/pages/:id = #show
/pages/:id/edit = #edit
...etc
How can I go about making it so that the url for the #show action of the pages controller looks like '/:id', without the '/pages/' prefix? should I exclude #show from resources :page & create a get route + alias for it separately? or is there a way to do it from inside the resources :page block? Thanks in advanced.
EDIT:
Changed it to:
resources :pages, except: [:show] do
resources :sections
end
get '/:id', to: 'pages#show'
& rerouting non-existing :ids' to 404 for now, let me know if there's a better solution. Thanks.

get '/:id', to: 'pages#show', as: 'page'
Make sure this is at the bottom of your routes.rb file, otherwise it is going to hijack requests to other routes.
This also gives you page_url and page_path helper methods. But to use them you must exclude show action from previous routes.
resources :pages, except: [:show]

Related

How to use named routes when using FriendlyId at the root path in Rails

I have a basic Page model in Rails that I'm using with FriendlyId to allow admins to create pages like "/about" or "/contact".
I have the following in my routes file (config/routes.rb) to ensure that the slugs for each page appear at the root of the site, such as https://example.com/about, etc:
resources :pages, except: [:show]
resources :pages, only: [:show], path: "/"
The problem is, with this approach, I can't use the normal named route like page_path(#page) in my views(or tests or controllers for that matter) because that routes to "/pages/about" and I get a "No route matches [GET] pages/about" error.
I could do both routes in my routes file so that "/pages/about" and "/about" work like this:
resources :pages
resources :pages, only: [:show], path: "/"
But, that creates an SEO duplicate content problem. I suppose I could create a helper that sets the rel="canonical" url for each page in the html header, but that also feels like a hack. I'd prefer for there to just be 1 version of each page at the root and also have a named route such as "page_path" or "root_page_path" that I can use throughout my app.
The hack I've come up with for the time being is <%= link_to "#{page.slug}" %>, but not having a named route seems very brittle.
What is a more "correct" way to do this in Rails?
I expected something like this to work:
resources :pages, only: [:show], path: "/", as: "page"
But that doesn't work either. Nothing in the Rails guide on routing is really helping either.
You need top switch the order of their definitions:
resources :pages, only: [:show], path: "/"
resources :pages, except: [:show]
resources only give name to the first path with given url. However - you will have the problem now as the pages/:id path (for delete and update) has now no route helper (as it is normally the same as show).
EDIT: As mentioned in the comment - it will also automatically match /pages path to a show action with id equal to pages - not a great idea! Which leads to better option:
resources :pages, except: [:show]
get :id, to: "pages#show", as: :root_page
Which gives you root_page_path(#page) helper for :show action and page_path(#page) for :update and :delete

Resources are not creating routes. Can only manually route in my rails app

Rails.application.routes.draw do
resources :users, only: [:index]
end
This is how I have my routes set up in my project. However it is not getting the route and I get an error:
No route matches [GET] "/index"
However my code below gives me no issues
Rails.application.routes.draw do
get "/index", to: "users#index"
#resources :users, only: [:index]
end
I am not sure what I am doing wrong. My controller and view files are set up properly, it just won't let me use resources for my routes. Any suggestions?
This particular code is
Rails.application.routes.draw do
resources :users, only: [:index]
end
generating a route for you with rails convention. By convention I mean that you have to send a GET request to /users in order to work. If you want to get users with /index you should use the second chunk of code you provided.
Basically
Rails.application.routes.draw do
get "/index", to: "users#index"
end
is rerouting your index request to user index, and just telling rails to where to find it.

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

Rails custom and default routes

I'm trying to define custom routes to my controller and I need to use some of the default routes too. Is there any simple solution?
So far I've something like this
resources :users do
member do
get 'users/:id', to: 'users#show'
delete 'users/:id', to: 'users#destroy'
end
collection do
post 'users', to: 'users#create'
post 'users/login', to: 'users#login'
end
end
resources :users, :only => [:show, :destroy, :create, :login]
I don't need nor want the index route but with this settings it's still trying to route GET users/ to user_controller index method.
I know that there is probably some simple and obvious answer but I'm not able to find it.
Thank's in advance.
You got your routes wrong. The resources :users generates seven default routes which include the index route as well. You need to tweak the code to below
resources :users, :only => [:show, :destroy, :create] do
collection do
post 'login', to: 'users#login'
end
end
Note:
If you noticed, I've removed the custom routes for show,create and delete as they are generated by default.
Your first line defines the route to the index action. Define a resource once only. Read the routing guide.
resources :users, :except => [:index] do
collection do
post 'users/login', to: 'users#login'
end
end
Run rake routes from the command line in your project root folder to see all your route definitions.

Can I get a controller to show up in the url under a different name?

I have a controller called "Pages". Can I make it show up in the url bar under a different name? For example, when I render the 'show' template, it shows up under this url: localhost:3000/pages/:id. Could I make it show up as localhost:3000/people/:id? I only care about the 'show' url; the other urls aren't that important.
routes.rb
get "pages/results"
get "pages/index" => "pages#index", as: "index_page"
resources :pages do
resources :categories
end
Add this your routes:
get '/people/:id', to: 'pages#show'
And remove the old show route from the resource:
resources :pages, only: [:index, :new, :create, :edit, :update, :delete] do
resources :categories
end
See: Rails guides about rounting
You could use like this:
get '/pages/:id' => "pages#show", path: 'people/:id'
This way you can access particular show page in the browser.
Hope this helps you.

Resources