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