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
Related
I'm new to Rails and I have been following a tutorial.
I have been fiddling around with routes.rb and now in total confusion about when it looks for show method and when for index method if not explicitly mentioned?
Routes are simply like regexes on steroids. They have priority in the order they are defined and match the request method, URI and any other constraints that you have added.
get '/posts', to: 'posts#index'
get '/posts/:id', to: 'posts#show'
The key difference to the routes above is that the regular expression which the path of request uri must match is different. '/posts/:id' includes a named segment which would match:
GET /posts/11
GET /posts/gobligook
But not:
GET /posts
GET /posts/1/foo
GET /posts/foo/bar
The full conventional set of CRUD verbs are:
get '/posts', to: 'posts#index' # all posts
get '/posts/new', to: 'posts#new' # form to create a post
post '/posts', to: 'posts#create' # create a post from a form submission
get '/posts/:id', to: 'posts#show' # show a single post
get '/posts/:id/edit', to: 'posts#edit' # form to edit a post
put '/posts/:id', to: 'posts#update' # for legacy compatibility
patch '/posts/:id', to: 'posts#update' # update a post from a form submission
delete '/posts/:id', to: 'posts#destroy' # delete a post
In Rails flavor REST the action is implicitly derived from the path and method.
Only the new and edit methods which are used to render forms actually explicitly add the action in the path - which is because they act on a collection or a member of a collection.
Note that the '/posts/new' route must be declared before get '/posts/:id' or the show route would match the request first (routes have priority in the order they are defined). This does not apply to get '/posts/:id/edit' since the pattern is different.
Of course typing out all those routes is really tedious so rails provides the resources macro that does this for you:
resources :posts
Both index and show are GET method, but the difference is index is collection type and show is member type. Which means index does not expect any parameter in the url, but show expects id param in the url.
EX:
Index: /posts
Show: /posts/:id
Rails chose convention over configuration. That's why the actions are not explicitly named.
Here is the complete list of the expected actions for a given controller: http://edgeguides.rubyonrails.org/routing.html#crud-verbs-and-actions
I'm looking at this tutorial: https://www.railstutorial.org/book/sign_up
We get on to rails resources.
config/routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
resources :users
end
app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def new
end
end
app/views/users/show.html.erb
<%= #user.name %>, <%= #user.email %>
There is also this handy table of telling us how ruby will handle the various requests to the Users resource.
I have two questions here.
How does RoR know when accessing the /users, /users/1 etc urls, what to actually use the index, show methods.
More importantly, - when the show method is called, how it does it know the give the show.html.erb view to browser? What if I wanted to return a different view?
1. Rails knows which methods to use based on the HTTP request type (GET, POST, PUT, or DELETE) and the endpoint. So when you hit the '/users' endpoint with a GET request, it will use the index method. When you hit the '/users/:id' endpoint with a GET request, it will use the show method.
2. The show.html.erb view is used because the name matches the show method. To use a different view, just use match in the routes file like so:
match "users" => "users#show"
The example above would match the '/users' route to the '/user/:id' route.
The mechanism that is responsible for dispatching actions in response to requests is router. You define all the routes in config/routes.rb file as you said. Each line in this files define the request in clear way. resources is a shorthand to define a set of routes - all of them listed here.
There are two thins that distinct requests - the URL and the HTTP request type (GET, POST, PUT, DELETE). Based on these two things you can clearly direct the request to proper controller. Take a look on this one:
get 'help' => 'static_pages#help'
This means: If you get a request of type get directed to url of value /help dispatch the request to controller static_pages and its action help. What happens in help action is a matter of code.
This is also an answer to your second question, how does Rails know what template should it render. Assume that we still work on above example of help action. If this action has no explicit render call, Rails will use its convention over configuration and search for a template that will be in directory called as the controller and in file name as the action name. Therefore, it will render the file that is in app/views/static_pages/help.html.erb. On the other hand, the developer can call render with explicit other file name, e.g.: render "products/show".
If you want to find more please take a look at these two Rails guides:
Layouts and rendering
Rails Routing
rails is said to have convention over configuaration. this is one of the strongest feature available in Rails.in another way. Smart and less code. Here when u say method name as show. rails by default will look for show.html.erb. if you want to explicitly render some other view. You can do this in your controller methods
render :new_view_name
Regarding the routes.
resources :users
This is very helpful when we have Rest calls ,crud operations.it creates 7 urls for crud. And how it differentiate is depending on http data type.
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...).
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.
What is the difference between collection routes and member routes in Rails?
For example,
resources :photos do
member do
get :preview
end
end
versus
resources :photos do
collection do
get :search
end
end
I don't understand.
A member route will require an ID, because it acts on a member. A collection route doesn't because it acts on a collection of objects. Preview is an example of a member route, because it acts on (and displays) a single object. Search is an example of a collection route, because it acts on (and displays) a collection of objects.
URL Helper Description
----------------------------------------------------------------------------------------------------------------------------------
member /photos/1/preview preview_photo_path(photo) Acts on a specific resource so required id (preview specific photo)
collection /photos/search search_photos_path Acts on collection of resources(display all photos)
Theo's answer is correct. For documentation's sake, I'd like to also note that the two will generate different path helpers.
member {get 'preview'} will generate:
preview_photo_path(#photo) # /photos/1/preview
collection {get 'search'} will generate:
search_photos_path # /photos/search
Note plurality!
1) :collection - Add named routes for other actions that operate on the collection. Takes a hash of #{action} => #{method}, where method is :get/:post/:put/:delete, an array of any of the previous, or :any if the method does not matter. These routes map to a URL like /users/customers_list, with a route of customers_list_users_url.
map.resources :users, :collection => { :customers_list=> :get }
2) :member - Same as :collection, but for actions that operate on a
specific member.
map.resources :users, :member => { :inactive=> :post }
it treated as /users/1;inactive=> [:action => 'inactive', :id => 1]
Short Answer:
Both the member and collection blocks allow you to define additional routes for your resources than the seven standard routes that Rails will generate for you.
A member block creates new routes on a single member of the resource.
A collection block creates new routes for a collection of that resource.
Long Answer
Rails provides the member and collection blocks so you can define custom routes for both the resource collection and the individual resource.
Here's how you'd typically define routes for the article resource.
resources :articles
This creates the following routes.
➜ bin/rails routes -g article
Prefix Verb URI Pattern Controller#Action
articles GET /articles(.:format) articles#index
POST /articles(.:format) articles#create
new_article GET /articles/new(.:format) articles#new
edit_article GET /articles/:id/edit(.:format) articles#edit
article GET /articles/:id(.:format) articles#show
PATCH /articles/:id(.:format) articles#update
PUT /articles/:id(.:format) articles#update
DELETE /articles/:id(.:format) articles#destroy
But let's say you are writing your articles in markdown, and need to see a preview of the article as you write it.
You could create a PreviewController and display the article's preview using its show action, but it's convenient to add a preview action on the ArticlesController itself.
Custom Member Routes
Here's how you define the preview route on the ArticlesController using the member block.
resources :articles do
member do
get 'preview'
end
end
It adds a new route that directs the request to ArticlesController#preview action. The remaining routes remain unchanged. It also passes the article id in params[:id] and creates the preview_article_path and preview_article_url helpers.
➜ bin/rails routes -g article
Prefix Verb URI Pattern Controller#Action
preview_article GET /articles/:id/preview(.:format) articles#preview
... remaining routes
If you have a single member route, use the short-hand version by passing the :on option to the route, eliminating the block.
resources :articles do
get 'preview', on: :member
end
You can go one step further and leave out the :on option.
resources :articles do
get 'preview'
end
It generates the following route.
➜ bin/rails routes -g preview
Prefix Verb URI Pattern Controller#Action
article_preview GET /articles/:article_id/preview(.:format) articles#preview
There are two important differences here:
The article's id is available as params[:article_id] instead of params[:id].
The route helpers changes from preview_article_path to article_preview_path and preview_article_url to article_preview_url.
Custom Collection Routes
To add a new route for the collection of a resource, use the collection block.
resources :articles do
collection do
get 'search'
end
end
This adds the following new route. It will also add a search_articles_path and search_articles_url helper.
search_articles GET /articles/search(.:format) articles#search
If you don't need multiple collection routes, just pass :on option to the route.
resources :articles do
get 'search', on: :collection
end
This will add the same route as above.
Conclusion
Rails allows you to break out of its convention of using seven resourceful routes using the member and collection blocks. Both allow you to define additional routes for your resources than the standard seven routes.
A member block acts on a single member of the resource, whereas a collection operates on a collection of that resource.
Source: Define New Routes Using the Member and Collection Blocks