how to remove action and controller from url in rails link_to - ruby-on-rails

Here is my link_to
<%= link_to sub_category.name, controller: :posts, action: :product, id: "#{sub_category.slug}-#{sub_category.id}" %>
Which is pointing to the url
http://localhost:3000/posts/product/fifith-category-s-sub-category-2
I need the url as follows
http://localhost:3000/fifith-category-s-sub-category-2
How can i do it.
my route.rb
resources :posts
match ':controller(/:action(/:id))(.:format)', via: [:get,:post]

what #MarekLipka suggests is correct but defining your routes like this will take up all the single level namespace in your app i.e. "/anything" will route by default to posts#product.
I recommended using some form of identifier to figure out which routes should go to posts#product. What will work for you depends on why you want to do this. Couple of options are:
Use a short namespace:
scope '/pp' do
get ':id', to: 'posts#product
end
# "/pp/:id" routes to 'posts/product'
# pp is a random short name I picked, it could be anything
# link
<%= link_to sub_category.name, "pp/#{sub_category.slug}-#{sub_category.id}" %>
Use a constraint:
get ':id', to: 'posts#product`, constraints: { :id => /sub\-category/ }
# only id's with 'sub-cateogry' route to 'posts/product'
# link (assuming that sub_category.slug has 'sub-category' words in it)
<%= link_to sub_category.name, "#{sub_category.slug}-#{sub_category.id}" %>

If you want path /:id match your posts#product, you should have something like this in your routes:
resources :posts
match ':id', to: 'posts#product`, via: :get
match ':controller(/:action(/:id))(.:format)', via: [:get, :post]

Related

Link_to pointing to static route

I've created a controller Pages and some actions for simple pages (contact us, for instance), then I went to routes.rb and created a route to allow users to go directly to /contactus, instead of /pages/contactus.
How can I point link_to to the action, but still getting the right route url?
get :contact_us, to: 'pages#contact_us'
or
get :contact_us, controller: :pages, action: :contact_us
this will generate path contact_us_path or url contact_us_url
HEARE MORE ABOUT ROUTES IN RAILS
#config/routes.rb
resources :pages, path: "", only: [] do #-> has to be above everything in routes file
collection do
get :contact_us #-> url.com/contact_us
get :about #-> url.com/about
end
end
root ...
You'd link to it as follows:
<%= link_to "Contact", pages_contact_us_path %>
You can do this:
get '/contactus', to: 'pages#contactus'
Your link can be:
<%= link_to "Contact Us", contactus_path %>
For more information, see: http://guides.rubyonrails.org/routing.html#connecting-urls-to-code
This is the syntax for a simple route using the contactus action in the pages controller:
get '/contactus' => 'pages#contactus'
or if you want a simpler name for your path:
get '/contactus' => 'pages#contactus', as: :contact

Any way to change new_post_path's default "/new" url?

TLDR; I need to have my new_topic_post_path link to /tennis/publish instead of /tennis/new
I have defined a custom route in routes.rb:
match '/:topic_id/publish', to: 'posts#new', via: [:get, :post]
But still new_topic_post_path(topic) returns a link:
http://localhost:3000/tennis/new
However, for cosmetical reasons I need the url to look like this:
http://localhost:3000/tennis/publish
Any ideas? Big appreciations for any answers. Thanks in advance.
(Also... if that is not possible, is there any way to add string in link_to, such as: link_to post.name, post(/publish) to achieve similar result? I tried countless variations of that, but couldn't find a way.)
Edit: Also, I'm having the links in
<% all_topics.sort { |a,b| a.name <=> b.name }.each do |topic| %>
<%= link_to topic.name, new_topic_post_path(topic) %>
<% end %>
So straight link_to "tennis/publish isn't suitable.
match '/:topic_id/publish', to: 'posts#new', via: [:get, :post], as: publish_topic
Then use publish_topic_path route helper.
Also you can do:
resources :posts, path_names: { new: 'publish' }
Try this...
resources :tennis, path_names: { new: 'publish' }
I'm not sure how to do it for all, though.
You need to take advantage of the :as option, which is used to generate routing helpers, in your routes.rb file, like so:
match '/:topic_id/publish', to: 'posts#new', via: [:get, :post], as: 'new_topic_post'
You can read more about options for the #match method here: http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-match

custom route in rails 4 not working

I've created custom routes to route to News model
resources :news, only: [:index] do
collection do
get 'page/:page', action: :index
end
end
get "news/:id(/p/:p)", to: 'news#show', as: 'news'
generate url like this
http://localhost:3000/news/4/page/2 index.html.erb is right
and show.html.erb
<%= link_to 'news', news_path(#news, '2')%>
I hope generate url http://localhost:3000/news/4/p/2
but generate http://localhost:3000/news/4?p=2
I think you've got a route conflict, change this:
get "news/:id(/p/:p)", to: 'news#show', as: 'news'
to this:
get "news/:id(/p/:p)", to: 'news#show', as: 'news_page'
and the use this link:
<%= link_to 'News', news_page_path(#news, '2')%>

Routes with optional params in Rails

I'm trying to setup a route that looks like this: acme.com/posts/:category/:status. Both :category and :status are optional. I wrote many variations, but none worked:
resources :posts do
match '(/:category)(/:status)', to: 'posts#index', as: 'filter', on: :collection
end
# Category Links
link_to "Questions", filter_posts_path(:questions)
link_to "Suggestions", filter_posts_path(:suggestions)
# Status Links
link_to "Published", filter_posts_path(params[:category], :published)
link_to "Draft", filter_posts_path(params[:category], :draft)
The idea is to be able to 1) filter by category, 2) filter by status, and 3) filter by both category and status if both are available. The current setup has also broken my /posts/new path, always redirecting to posts#index.
I had this variation and it seems working fine:
namespace :admin do
resources :posts, :except => [:show] do
collection do
get "/(:category(/:status))", to: "posts#index", as: "list", :constraints => lambda{|req|
req.env["PATH_INFO"].to_s !~ /new|\d/i
}
end
end
end
= CONTROLLER=admin/posts rake route
list_admin_posts GET /admin/posts(/:category(/:status))(.:format) admin/posts#index
You can use the more RESTful resources :posts (in config/routes.rb) and send the params in the query string.
With that approach, all parameters are optional and you're not limited to using predefined parameters.
Do this works for you?
resources :posts do
collection do
match '/:category(/:status)', to: 'posts#index', as: 'filter'
match '/:status', to: 'posts#index', as: 'filter'
end
end
Hope at least it helps!
You could try something like this:
match '/filter/*category_or_status' => 'posts#index', as: 'filter'
With this you can build your own filter path. Then you could parse params[:category_or_status] in your controller and get the category or status if they are given.

:as in rails routes.rb

In config/routes.rb, I tried both:
root :to => 'things#index', :as => 'things'
and
root :to => 'things#index'
When I hit http://localhost:3000/, both approaches work, and nothing seems to be different.
What is the :as option used for?
The :as option forms a named route.
Usually it's used in a non-root route. For example:
match '/search' => 'search#search', :as => 'search' # SearchController#search
You could then do something like:
<%= link_to search_path, 'Click Here to Search!' %>
search_path and search_url are defined because of the :as
For a root route, you don't really need :as because the the URL helpers root_path and root_url are defined for you by Rails.
Rails 4 compatible.
In path_to_your_app/config/routes.rb
get "/profile/edit" => "users#profile_edit", :as => "edit_me"
Since ruby 2.0 you can use:
get "/profile/edit", to: "users#profile_edit", as: "edit_me"
In path_to_your_app/app/views/**in required view
<%= link_to "Edit profile", edit_me_path %>
Do not use match if you aren't sure you need it:
It creates a vulnerability when you use it in next pattern:
match ':controller/:action/:id'
From documentation:
You should not use the match method in your router without
specifying an HTTP method. If you want to expose your action to both
GET and POST, add via: [:get, :post] option. If you want to expose
your action to GET, use get in the router:
Instead of: match "controller#action"
Do: get "controller#action"
Read more about:
About match
http://github.com/rails/rails/issues/5964
About routes mapping
http://apidock.com/rails/v4.0.2/ActionDispatch/Routing/Mapper/Base/match
http://api.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html
About routes in general
http://api.rubyonrails.org/classes/ActionDispatch/Routing.html
The :as option creates a named path. You can then call this path in your controllers and views (e.g. redirect_to things_path). This isn't very useful for the root path (as it already named root), but is very useful for new routes you add.

Resources