Rails routes change URL with ressources - ruby-on-rails

I have the following in my routes:
resources :collection_pages, :only => [:show, :index]
Right now its going to wwww.mysite.com/collection_pages for index
and collection_pages/:id for show
I need it to go to /collections instead for index
and /collection/:id for show
I tried path: :collections , but its not behaving as I'd like.
What's the best way to achieve this using ressources?

Along with the SO answer #Tamer.Shlash notes, you could use custom matchers in your routes file:
match '/collection', to: 'collection_pages#index', as: 'collection_index'
match '/collection/:id', to: 'collection_pages#show', as: 'collection_show'
Adding the as: 'xxxx' to the match allows you to use friendly path and url helpers in your views:
redirect_to collection_index_path

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

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

Remove controller from friendly URL

I have written freindly URLs for the show action of the School Resource but now have
before i had ;
http://webaddress/schools/2
and now i have;
http://webaddress/schools/school_name
However, i want
http://webaddress/school_name
My config routes look like this for the resource;
resources :schools do
collection do
match 'search' => 'schools#search', via: [:get, :post], as: :search
end
end
How can i achieve that? thank you
Add this at the last your routes file:
match ':id' => 'schools#show', via: [:get]
A more conventional way would be to use the path: option in your route resources, like this:
#config/routes.rb
...
resources :schools, path: "", only: :show #-> has to go at end of file!
This will give you the ability to add different methods to this, as well as keeping with Rails conventions :)

make a custom url for create action with RESTful routing

In Rails 4 I'm trying to make a custom root for a particular action in the users controller, so i want my restful resources for users still like they are, but change only the url for the create action and make it to be for example /account/register. I'm trying do this as the follow but it seem not work :
resources :users, except: [:create] # first i eliminate creation of create root
resources :users, path: "account/register", as: :users, only: [:create] # then i just try to make a custom route for only create action
i want still using users_path and not change any of my routing helper in the view, please any idea ?
Try:
match '/account/register' => 'user#create', via: :post
How about:
post "/account/register" => "users#create", as: :users
This will create a route where /account/register points to UsersController#create. This can be referenced with users_path.

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