Customizing resource routes for every action - ruby-on-rails

I have a resources :posts. How can I customize it's paths to the following and also ability to call it with the normal resource path names:
URL Controller action Helper function
'q' 'posts#index' posts_path
'q/(:id)' 'posts#show' post_path(:id)
'ask' 'posts#new' new_post_path
'q' 'posts#create' posts_path
Here is what I've tried and doesn't work as the expected result above...
get 'q' => 'posts#index', as: :posts
get 'q/(:id)' => "posts#show", as: :post
get 'ask' => 'posts#new'

You're presumably getting an error because you're trying to assign a route name that is already in use.
The resources posts call results in a definition for the posts and post routes. If you change your as: .. clause to reference different (unused) names, you will no longer get that error.

try resources :posts path => 'q'

Related

How to remove /posts/ from URL?

How can I also show a blog post without /posts/ in the URL?
http://www.anthonygalli.com/posts/i-walk-the-line
http://www.anthonygalli.com/posts/50-shades-of-galli
http://www.anthonygalli.com/posts/tips-for-regaining-momentum
Shortened Version (Goal of Question):
http://www.anthonygalli.com/i-walk-the-line
http://www.anthonygalli.com/50-shades-of-galli
http://www.anthonygalli.com/tips-for-regaining-momentum
I have post as a MVC.
routes.rb
resources :posts
get 'about' => 'posts#about'
get 'feed' => 'posts#feed'
get 'subscribe' => 'posts#subscribe'
Change your routes.rb to:
resources :posts, path: '/' do
collection do
get 'about'
get 'feed'
get 'subscribe'
end
end
For documentation on Rails routing check: http://guides.rubyonrails.org/routing.html
Your routes should be updated to look something like this:
resources :posts
get 'about' => 'posts#about'
get 'feed' => 'posts#feed'
get 'subscribe' => 'posts#subscribe'
get ':id' => 'posts#show', :as => :post_by_slug
That as option will be important for linking to your new route if you want to link to the /post/-less paths:
<%= link_to post.title, post_by_slug_path(post) %>
P. S. I believe that the new route will need to be listed last in your routes so that the routes before it can have precedence. (Otherwise, trying to visit /about would try to load a post with a slug named about instead of the posts#about action. You should try this and see if that's true.)
Resource generates the standard CRUD urls, so you have to specify the posts route specifically. Something like this
get '/desired-url' => 'posts#index'

Rails routes: Nested, Member, Collection, namespace, scope and customizable

I am trying to understand more about Rails routes.
Member and Collection
# Example resource route with options:
resources :products do
member do
get 'short'
post 'toggle'
end
collection do
get 'sold'
end
end
Namespace and Scope
# Example resource route within a namespace:
namespace :admin do
resources :products
end
scope :admin do
resources :products
end
Constraints, Redirect_to
# Example resource route with options:
get "/questions", to: redirect {|params, req|
begin
id = req.params[:category_id]
cat = Category.find(id)
"/abc/#{cat.slug}"
rescue
"/questions"
end
}
Customization:
resources :profiles
original url from resource profiles for edit.
http://localhost:3000/profiles/1/edit
I want to make it for users available only through click edit profile and see url like in below.
http://localhost:3000/profile/edit
Also, is there advanced routing, How most big companies design their routes in rails ? I would be really glad to see new kind of routes if there exist.
Thank You !
**Collection & Member routes**
A member route requires an ID, because it acts on a member.
A collection route doesn't require an ID because it acts on a
collection of objects
:member creates path with pattern /:controller/:id/:your_method
:collection creates path with the pattern /:controller/:your_method
For example :
map.resources :users, :collection => { :abc => :get } => /users/abc
map.resources :users, :member => { :abc => :get } => /users/1/abc
**Scopes & Namespaces routes**
namespace and scope in the Rails routes affect the controller
names, URIs, and named routes.
The scope method gives you fine-grained control:
scope 'url_path_prefix', module: 'module_prefix', as: 'named_route_prefix' do
resources :model_name
end
For Example :
scope 'foo', module: 'bar', as: 'baz' do
resources :posts
end
produces routes as :
Prefix Verb URI Pattern Controller#Action
baz_posts GET /foo/posts(.:format) bar/posts#index
POST /foo/posts(.:format) bar/posts#create
new_baz_post GET /foo/posts/new(.:format) bar/posts#new
edit_baz_post GET /foo/posts/:id/edit(.:format) bar/posts#edit
baz_post GET /foo/posts/:id(.:format) bar/posts#show
PATCH /foo/posts/:id(.:format) bar/posts#update
PUT /foo/posts/:id(.:format) bar/posts#update
DELETE /foo/posts/:id(.:format) bar/posts#destroy
The namespace method is the simple case — it prefixes everything.
namespace :foo do
resources :posts
end
produces routes as :
Prefix Verb URI Pattern Controller#Action
foo_posts GET /foo/posts(.:format) foo/posts#index
POST /foo/posts(.:format) foo/posts#create
new_foo_post GET /foo/posts/new(.:format) foo/posts#new
edit_foo_post GET /foo/posts/:id/edit(.:format) foo/posts#edit
foo_post GET /foo/posts/:id(.:format) foo/posts#show
PATCH /foo/posts/:id(.:format) foo/posts#update
PUT /foo/posts/:id(.:format) foo/posts#update
DELETE /foo/posts/:id(.:format) foo/posts#destroy
**Constraints & Redirect**
Rails routes are executed sequentially, you can mimic conditional
login in the following manner:
match '/route' => 'controller#action', :constraints => Model.new
match '/route' => 'user#action'
The first line checks whether the conditions of the constraint are met (i.e., if the request is emanating from a Model domain). If the constraint is satisfied, the request is routed to controller#action.
We can add constraints to routes for multiple uses like for ip-matching, params matching, restrict format parameter, request-based restrictions etc as :
- ip-matching
=> resources :model, constraints: { ip: /172\.124\.\d+\.\d+/ }
- filtering id params
=> match 'model/:id', to: 'model#show' ,constraints: { id: /\d+/}, via: :get
- restrict format params
=> match 'model/:id', to: 'model#show' ,constraints: { format: 'json' }, via: :get
- request-based constraints
=> get 'admin/', to: 'admin#show', constraints: { subdomain: 'admin' }
Use a singular resource for it:
resource :profile
and in controller manipulate the profile of current user.
As for complex routes - usually namespaces, nested resources with shallow routes and custom actions are all that is needed.
You can go through this answer which answers you first part of the question.
To answer second part of your question. You can treat "profile" as your singular resource (the singularity of the noun itself represents a singular resource). For a detailed description you can refer to this link.

Named routes inserting a . instead of a /

I've been having trouble with named routes in rails 4 (Named route for non resource nesting).
I've moved onto something else, but still struggling with the same problem of named routes for non resource urls.
This is my route from rake routes:
GET /messages/:id/report/:reply_token(.:format) messages#report
messages POST /messages(.:format) messages#create
and my routes.rb
resources :messages, only: [:create] do
member do
get 'report/:reply_token', :action => 'report'#, :as => :message
end
end
Because of the problem I had in my post linked at the top, I'm trying to get a url to the /messages/:id/report/:reply_token route by doing the following:
"#{messages_url(#message, :host => "localhost:3000")}/report/#{#message.reply_token}"
But it's giving me this:
http://localhost:3000/messages.110/report/6bBw22TdaRYcQ3iVzW1ZwA
Why is there a . between the 'messages' and the '110' (message_id)?
Instead of #message, I've also tried #message.id in the messages_url(). I've also tried this: report_message_path(message_id: #message.id, reply_token: #message.reply_token) but got the same error as in my question linked above. I've also tried message_url() instead but it gives undefined method 'message_url'.
You are mixing up routes. messages_url is to generate a URL for create action which does not have ID in its route. Rails assumes 110 is the format and uses the second route (which is named as messages)
messages POST /messages(.:format)
As a solution, name your route like this and also add show action
resources :messages, only: [:create,:show] do
member do
get 'report/:reply_token', :action => 'report' , :as => :custom_message
end
end
And,
custom_message_url(#message, :host => "localhost:3000")
More about naming routes here.
Answerd here already - Rails _path helper generating path with format not id

Rails routes for get request with query params

I need a route to accept a request reports#show with an attached :query parameter and I can't figure out how to write it. It needs to respond to this link in my view:
= link_to report_path(query: params[:query]) do
config/routes.rb
resources :reports do
resources :chapters
resources :pages
end
Tried variations of: get '/reports/:id/:query', :as => 'reports_query' but I keep getting:
Routing Error
No route matches {:action=>"show", :controller=>"reports", :query=>"europe"}
Project is mostly RESTful but I'll take anything that works at this point. Thanks for any help.
You should define your route to query with code like this
# routes.rb
resources :reports do
get ':query', to: 'reports#show', on: :member, as: :query
end
It will generate path helper you can use that way
= link_to 'Query Report', query_report_path(#report, query)
I went through the same problem here, and I solved it using the default param while defining my routes.
get :twitter_form, defaults: { form: "twitter" }, as: :twitter_form, to: "campaigns#show"

Rails routing. Singular resource

I've got Rails routing problem. I would like to use singular resource with user controller but it doesn't work as I expected. Here is the fragment of my routes.rb file:
scope :module => "frontend" do
root :to => "home#index"
resource :user, :controller => "user"
get "/sign_up" => "user#new"
get "/sign_in" => "user#sign_in"
get "/sign_out" => "user#sign_out"
post "/authenticate" => "user#authenticate"
resources :articles
resources :article_categories
end
I thought it will work when I'll use for example "/user" or "/user/new" URL but it didn't. I get a routing error:
No route matches {:controller=>"frontend/user"}
The 'rake routes' command output is:
user POST /user(.:format) frontend/user#create
new_user GET /user/new(.:format) frontend/user#new
edit_user GET /user/edit(.:format) frontend/user#edit
GET /user(.:format) frontend/user#show
PUT /user(.:format) frontend/user#update
DELETE /user(.:format) frontend/user#destroy
sign_up GET /sign_up(.:format) frontend/user#new
sign_in GET /sign_in(.:format) frontend/user#sign_in
sign_out GET /sign_out(.:format) frontend/user#sign_out
authenticate POST /authenticate(.:format) frontend/user#authenticate
What is interesting, when I add route for index action in user controller, like this:
scope :module => "frontend" do
root :to => "home#index"
resource :user, :controller => "user"
get "/user" => "user#index"
get "/sign_up" => "user#new"
get "/sign_in" => "user#sign_in"
get "/sign_out" => "user#sign_out"
post "/authenticate" => "user#authenticate"
resources :articles
resources :article_categories
end
...it works!
But index action is not defined in user controller!
'rake routes' command returns double line for GET /user
GET /user(.:format) frontend/user#show
GET /user(.:format) frontend/user#index
so I suppose that's not the solution. Other actions assigned to '/users' URL don't work.
Is it necessary to define the route for the index action like
get "/controller_name" => "controller_name#index"
What am I doing wrong?
Defining a singular resource in your routes will not generate a route to an index action by design. The singular resource implies you're always going to lookup this resource without specifying an ID and consequently a get to index for a singular resource just doesn't make logical sense. So, a GET to your url "/user" will route to a show action for that singular resource and not an index.
EDIT: Since your issue isn't obvious, I'd simplify your routes until you can at least hit the controller you'd expect and then build from there.
config/routes.rb
scope :module=>"frontend" do
resource :user
end
#ensure you don't have any other user routes listed before this that would match "/user".
app/controllers/frontend/users_controller.rb
module Frontend
class UsersController < ApplicationController
def show
raise "in frontend/show"
end
end
end
Thanks a lot for help! I found the bug.
The routing error was caused by the following line of the layout html file
<%= auto_discovery_link_tag(:rss, {:action => "index"}, {:title => "RSS"}) %>
I was looking for errors in the erb view files but I forgot about the layout.
I must remember to check the entire view layer in such situations.

Resources