I have a search route which I would like to make singular but when I specify a singular route it still makes plural controller routes, is this how it's supposed to be?
resource :search
Gives me
search POST /search(.:format) {:action=>"create", :controller=>"searches"}
new_search GET /search/new(.:format) {:action=>"new", :controller=>"searches"}
edit_search GET /search/edit(.:format) {:action=>"edit", :controller=>"searches"}
GET /search(.:format) {:action=>"show", :controller=>"searches"}
PUT /search(.:format) {:action=>"update", :controller=>"searches"}
DELETE /search(.:format) {:action=>"destroy", :controller=>"searches"}
Plural controller "searches"
I only have one route really... to create a search:
So I did: match "search" => "search#create"
I'm just wondering for the future if I'm still supposed to keep the controller plural? Rails 3.0.9
Yes, that's how it's supposed to be. Quote from the Rails Guide on Routing:
Because you might want to use the same controller for a singular route
(/account) and a plural route (/accounts/45), singular resources map
to plural controllers.
http://edgeguides.rubyonrails.org/routing.html#singular-resources
You could fix this by setting the plural of "search" to be uncountable so in config/initializers/inflections.rb
ActiveSupport::Inflector.inflections do |inflect|
inflect.uncountable %w( search )
end
This should now allow search to only be used
Is the search really a resource? If it is, then what you a creating is an instance of a model with a type of "search", in which case the plural controller "searches" makes perfect sense.
However, if it's a controller that doesn't have multiple models, then maybe not. In which case, you don't need to define the routes with resource :search you can simply use get 'search/create' to tell the router to answer "search/create" to the 'create' action in your 'search' controller.
Do you want only one route to be generated for the creation?
If so:
resource :search, :only => :create
The fact that the controller for the REST resource is named searches_controller is a convention (that you can change, by forcing the controller's name in the route with resource :search, :only => :create, :controller => :search, but it does not worth it...).
Related
When you type
rake routes
a bunch of routes come out, but where are they defined???
I know some are default, and how about the others?
For example, this is a script from a controller, I tried to take off the 's' from do_something, but can't make it work.... are they defined somewhere else too?
Also, when do they take parameters and when not, how I know it ? Thanks!
def hello
redirect_to do_things_shop_path(shop)
end
def do_things
end
Rails routing configurations are kept in config/routes.rb file.
Taking parameters depends on many things. rake routes will show with routes take parameters. Member actions will take parameters.
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
edit_post GET /posts/:id/edit(.:format) posts#edit
In the last line, you will url like posts/:id/edit. This path requires :id parameter. You can call this route many ways. One of them is like:
edit_post_path(#post)
If you want to create a custom action, (say under posts controller), you can declare it as follow:
match `/posts/:id/things_with_id`, :to => 'posts#do_things_with_id', :as => 'do_things_with_id
match `/posts/things_without_id`, :to => 'posts#do_things_without_id', :as => 'do_things_without_id
First one requires an ID while the second one does not. Call them accordingly:
do_things_with_id_path(#post)
do_things_without_id()
For a resource, you can create these easily using member & collection action. Member action needs id while collection action does not.
resources :posts do
member { get 'do_thing' }
collection { get do_things' }
end
hope you got it.
By the way, you must read the following guide if you want to understand these clearly.
http://guides.rubyonrails.org/routing.html
I want to have a namespaced controller called 'portal'.
in this will be nested resources such as companies and products.
I'd like routes like :
/portal/:company_id/product/:id to work
I can get
/portal/company/:company_id/product/:id to work but would like to eliminate the 'company' in the url
Hope that is clear. Please keep in mind that I need the namespaced module portal to exist.
I think you could use scope to achieve what you want. Perhaps like this:
namespace "portal" do
scope ":company_id" do
resources :products
end
end
That will generate the following routes:
portal_products GET /portal/:company_id/products(.:format) {:action=>"index", :controller=>"portal/products"}
POST /portal/:company_id/products(.:format) {:action=>"create", :controller=>"portal/products"}
new_portal_product GET /portal/:company_id/products/new(.:format) {:action=>"new", :controller=>"portal/products"}
edit_portal_product GET /portal/:company_id/products/:id/edit(.:format) {:action=>"edit", :controller=>"portal/products"}
portal_product GET /portal/:company_id/products/:id(.:format) {:action=>"show", :controller=>"portal/products"}
PUT /portal/:company_id/products/:id(.:format) {:action=>"update", :controller=>"portal/products"}
DELETE /portal/:company_id/products/:id(.:format) {:action=>"destroy", :controller=>"portal/products"}
Edit: Accidentally used resource instead of resources. Fixed now.
You can customize the routes to nearly whatever you want if you spell them out directly, like this:
match '/portal/:company_id/product/:id', :to => 'companies_products#show'
The :to part specifies the controller and action to use, something that should match what you have in your routes now. If you're not sure what that is, rake routes will tell you its specific interpretation.
The following link works in my app:
<%= link_to "invitation", :controller => :invitations, :action => :index %>
To follow restful conventions i changed the link to:
<%= link_to "invitation", index_invitation_path %>
The error that i get is:
undefined local variable or method `index_invitation_path'
Rake routes yields:
invitations GET /invitations(.:format) {:controller=>"invitations", :action=>"index"}
The page name is index.html.erb. The model is invitation.rb. The controller is invitation_controller.rb. Routes has resources :invitations. What am i missing?
Thanks!
Assuming you have the routing correct:
resources :invitations
Then the correct helper for the index action (with the url /invitations.html) is
invitations_path
You can see more information by running rake routes. It will display text like the following:
lists GET /lists(.:format)
{:action=>"index", :controller=>"lists"}
POST /lists(.:format)
{:action=>"create", :controller=>"lists"}
new_list GET /lists/new(.:format)
{:action=>"new", :controller=>"lists"}
edit_list GET /lists/:id/edit(.:format)
{:action=>"edit", :controller=>"lists"}
list GET /lists/:id(.:format)
{:action=>"show", :controller=>"lists"}
PUT /lists/:id(.:format)
{:action=>"update", :controller=>"lists"}
DELETE /lists/:id(.:format)
{:action=>"destroy", :controller=>"lists"}
root /(.:format)
{:controller=>"lists", :action=>"index"}
The above was from a route of my own (for a model called List). The route helper method is shown immediately before the HTTP method. You have to remember to append the _path to each helper method. For example the helper methods I could use are:
list_path(list)
edit_list_path(list)
new_list_path
lists_path
You'll need a route in your routes.rb file that defines a mapping to the invitations controller and the index action.
Typically this is created with a resources call
resources :invitations
Which creates several default routes, which you can see by running rake routes.
For single resources, you can also define it using a match call
match "invitations/:id" => "invitations#index", :as => index_invitation
The rails site has a great resource on routing that provides all the details: Routing from the Outside In
Update: Based on your updated question, your route includes an invitaions (notice the trailing 's') route - nothing with index or invitation. The index_ prefix is generated by the resources call when it creates the default routes for :invitations.
It looks like you've defined a custom get mapping for an invitation. While this may technically work, if you're aim is to support restful routes, use the resources method. And have a read of the Routing guide from rails it's very easy to follow and quite detailed.
type rake routes in your console and look at listing of available routes. Seems to be there is no such route index_invitation_path? maybe it named differently
I think you need "invitations_controller.rb" to contain InvitationsController. Plural.
Using Ruby on Rails 3's new routing system, is it possible to change the default :id parameter
resources :users, :key => :username
come out with the following routes
/users/new
/users/:username
/users/:username/edit
...etc
I'm asking because although the above example is simple, it would be really helpful to do in a current project I'm working on.
Is it possible to change this parameter, and if not, is there a particular reason as to why not?
In your route you can use
resources :user, param: :username
If I understand you correctly, what you want is to have the username instead of id in your url, right?
You can do that by overriding the to_param method in your model. You can get more information here.
For Ruby on Rails 4.1.4 (and possibly earlier versions) you need to do what both j.. and Ujjwal suggested:
1) In config/routes.rb, add:
resources :user, param: :username
2) In app/models/user.rb, add:
def to_param
username
end
In you only do #1 then all your routes will be correct, as can be seen from rake routes:
$ rake routes
Prefix Verb URI Pattern Controller#Action
user_index GET /user(.:format) user#index
POST /user(.:format) user#create
new_user GET /user/new(.:format) user#new
edit_user GET /user/:username/edit(.:format) user#edit
user GET /user/:username(.:format) user#show
PATCH /user/:username(.:format) user#update
PUT /user/:username(.:format) user#update
DELETE /user/:username(.:format) user#destroy
However the helper methods that construct a url based on a User instance will still include the id in the url, e.g. /user/1. To get the username in the constructed urls, you need to override to_param as in #2.
Although the answer has been accepted by the asker, but there is a simple approach to do this. Write this code in your controller.
authorize_resource :find_by => :username
and in your view, where you want to show the link, write this code.
<%= link_to "Username", user_path(u.username) %>
You don't need any other changes in your routes or controller.
UPDATE: This will only work if you are using CanCan gem.
Pass the user name as the input to the path helpers.
In your view code:
user_path(u.username) #/users/john
In your controller treat the id received as username:
def show
user = User.find_by_username!(params[:id])
...
end
I was reading Simply Rails by Patrick Lenz... maybe I missed something, it seems that whenever we put
map.resources :stories
in routes.rb
then immediately, the controller will have special convention and now Story is a RESTful resource? Maybe the author used the word resource but didn't mention that it is RESTful but they are the same thing?
Having that in routes means that you automatically get some standard routes that help you build a restful application. For example:
new_story GET /story/new(.:format) {:action=>"new", :controller=>"stories"}
edit_story GET /story/edit(.:format) {:action=>"edit", :controller=>"stories"}
story GET /story(.:format) {:action=>"show", :controller=>"stories"}
PUT /story(.:format) {:action=>"update", :controller=>"stories"}
DELETE /story(.:format) {:action=>"destroy", :controller=>"stories"}
POST /story(.:format) {:action=>"create", :controller=>"stories"}
Just having this one line in your routes file, gives you all these paths to use. You just have to make sure you provide the right functionality in new, edit, show, update, destroy and create actions of your stories controller and you will have a restful design.
In order to see what is available route-wise, you can go to your application folder and give the command:
rake routes
This is going to output all the paths available to you, based on what you have entered in your routes file.
BUT!!! If you have other actions in your controller they will NOT be found unless you introduce additional routes ABOVE that .resources line!
So if you have an action called turn_page in the stories controller you need to include a map.connect line before the map.resources line - as in this snippet:
map.connect 'stories/turn_page', :controller => 'stories', :action => 'turn_page'
map.resources :stories
Hope that helps someone! I got stuck for hours working on this one as all the examples are EITHER "regular" routes OR the REST set defined via the .resources statement!
Yes. Once you add that to your routes your Story controller will respond to the common REST verbs in the expected ways.