There must be an obvious answer to this, but I'm at a loss.
I have a Rails app which tracks sites. For whatever reason, localhost:3000/sites leads to my index page. However, localhost:3000/sites/index leads to my show page.
Why is this?
Below is the routes file:
Rails.application.routes.draw do
resources :sites
Below is the sites controller:
class SitesController < ApplicationController
def index
end
def show
end
end
In views/sites, there is the index.html.erb and show.html.erb files. The former displays at /sites, the latter displays at /sites/index (and /sites/show as one would expect).
Thanks for any help!
UPDATE:
When I rake routes, I get:
Prefix Verb URI Pattern Controller#Action
sites GET /sites(.:format) sites#index
POST /sites(.:format) sites#create
new_site GET /sites/new(.:format) sites#new
edit_site GET /sites/:id/edit(.:format) sites#edit
site GET /sites/:id(.:format) sites#show
PATCH /sites/:id(.:format) sites#update
PUT /sites/:id(.:format) sites#update
DELETE /sites/:id(.:format) sites#destroy
These routes are what one would expect, but I guess I'm just surprised that sites/index presumes index is an :id and therefore routes the request to show.
I suppose I had never explicitly encountered that behavior before.
There are 7 basic actions in a controller by default, only 2 of them are matched by name in the url - (new and edit). These 2 are HTML constructs, they are just a way of rendering a form.
The other 5 (index, show, update, create, destroy) are the more basic routes and do the work to display and modify resources. They are referenced by only two url patterns (the two patterns you mentioned above - eg '/sites' and '/sites/:id'). They are differentiated by the method that goes along with the request: (Patch, Post, Get, Delete). So, "/sites" would be used for create and index. "/sites/:id" would be used for show, destroy, and update.
The action in the controller is not referenced by the url exactly - the url pattern and the request method together are used to call the associated controller method.
In the request "/sites/index", as the string "index" is in the url, the only route that matches is one that has a variable after "/sites/". :id is just a variable, not necessarily an integer. Since the request was a GET, the first (and only) route match is sites#show. "index" will be the value of params[:id] passed into the show action.
This is the way routing works in Rails. Take a look at Rails routing to get a better understanding of how this works. Especially the
Rails resource routing section.
Generally when you setup a resource route as you did the urls would be as follows:
example.com/sites #=> index page
example.com/sites/:id #=> show page. A specific site, where :id would be the unique identifier
# Here's an example URL with a specific site
example.com/sites/stackoverflow
Your index page is at: localhost:3000/sites
Navigate to localhost:3000/rails/info/routes to see your full app routes in development mode.
Related
I have a simple question about rails.
I followed a tutorial (from CrashLearner).
In that tutorial we have a simple resource message that generates the regular following routes (excerpt from rake routes)
Prefix Verb URI Pattern Controller#Action
messages GET /messages(.:format) messages#index
POST /messages(.:format) messages#create
new_message GET /messages/new(.:format) messages#new
edit_message GET /messages/:id/edit(.:format) messages#edit
message GET /messages/:id(.:format) messages#show
PATCH /messages/:id(.:format) messages#update
PUT /messages/:id(.:format) messages#update
DELETE /messages/:id(.:format) messages#destroy
As I understand the route to get to the show action of this controller is like something /messages/17, I mean we have to put the :id of that particular message we want to view.
So, if I needed to redirect the user to this message view after he modified it (in the #update action) I should use:
redirect_to message_path(17)
But it turns out that omitting this :id actually works great:
redirect_to message_path
Why and how this last one work ?
Since this works from an action that actually received the :id param I suppose that the controller keep it in memory and pass it through by default under the hood when it is missing but I would like to understand where this behavior come from ?
I found nothing in the rails documentation.
Here is the github repository of the tutorial, so the exact specific place of the above line is here in this controller.
And I confirm that this works.
There is also a Comment resource that is nested from the previous Message resource.
As you can see in that controller on the update action, after updating a comment (which is nested within a message) the controller redirects to the message_path but in that case the :id parameter is present through the instance variable #message (and I learned that this works because the object Message respond to an .id method otherwise it should be #message.id)
I supposed that the reason that why here the :id is still passed is because we are in the Comments controller and the :id of another resource could not be passed under the hood, thus why it is explicitely written.
I don't have another explication..
Can anyone explain me why this works ?
I found this in Rails source:
Missing routes keys may be filled in from the current request's
parameters (e.g. +:controller+, +:action+, +:id+ and any other
parameters that are placed in the path).
So here :id exists in the current request params and it's used for this route.
If you define singular resource you will have show action without :id param
http://edgeguides.rubyonrails.org/routing.html#singular-resources
Something like resources :products will create 7 different restful routes for CRUD operations for resource products. For example: products GET /products(.:format) products#index
So restful route includes only controller name within itself and :id for operation like edit, show, update, delete.So as i get this, first requirement(in rails) for route(to be precisely URL) to be restful is that route can't contain action name? Q1
Second requirement for route to be restful is that action corresponding to route must "play by restful rules" in another word, for example a GET should not leave side-effects on the server, but just retrieve data. So if i have /products(.:format) products#index and within index action i saved something into DB, than above route is just looks like restful route but in fact it isn't?
When i create non-restful routes in rails for example: get ':controller/:action/:id' i only can see difference that i must explicitly write :action, so that ":action" makes this route non-restful?
To me seems that restful in rails is everything about CRUD? An second i don't need non-restful routes at all, when i can make a bunch of restful routes with construct like following(and other similar construct)?
resources :products do
member do
get 'preview'
end
end
From this point and i'm relatively new to all of this, reading a lot about REST concept, and if im right about my first question(Q1) is that only difference between restful and non-restful route in rails?
Ok I kind of understand this part: CRUD verbs and actions http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
and if I go to the route file of the example I have, I also see a resources :orders in it.
But now in the view of a partial names _carts I am seeing this code:
<%= button_to "Checkout" , new_order_path, method: :get %>
What confuses me is the new_order_path ? Where did that come from? What Rails convention rule is allowing us to right this? Especially where did that "new" come from?
When you use resources :orders in the routes, Rails creates 7 routes for new, create, show, update, destroy, list, and edit. All of them are given names, and new_order_path/new_order_url is related to the new action.
These routes are described at the http://guides.rubyonrails.org/routing.html#paths-and-urls
Those path helpers are automatically generated for resources defined in your routes.rb. You can check what route helpers are available by executing rake routes at the command line. They are shown in the left-most column in the table that prints out.
The general pattern of the paths that are created are like so by default:
new_{singular form of resource}_path - Routes to new on GET
edit_{singular form of resource}_path - Routes to edit on GET
{singular form of resource}_path - Routes to show on GET, destroy on DELETE, update on PUT (Soon to be PATCH in Rails 4)
{plural form of resource}_path - Routes to index on GET and create on POST.
There's also helpers that end in _url instead of _path that provide absolute URLs instead of relative paths. The particular action that is hit in your controller depends on the HTTP verb (GET, PUT, POST, DELETE, etc.) used when visiting those URLs.
I have an application in RAILS, it is composed of a set of API, a basic website, and an admin dashboard.
For the API routing I have no problems, as they belong to a model and a controller and are compliant with the RAILS RESTful pattern (a controller for each model, and a method for each HTTP method).
What I'm not comfortable with is writing routes and controllers for website.
The main website is at / so the default route is root :to => "home#index"and I have
Routes for the website pages which look like
get "home/index"
get "map/index"
get "api/index"
get "cgu/index"
get "legal/index"
Which I think it is not good, as I have a controller per view and I need to define a get for each views.
Now for the dashboard I tried a different approach.
It is at /dashboard, the default route is match "dashboard" => "dashboard#index" and here is few pages as an examples
get "dashboard/index"
get "dashboard/users"
get "dashboard/users_stats"
get "dashboard/routes"
get "dashboard/routes_stats"
get "dashboard/charts"
get "dashboard/financial"
So for the dashboard I have a massive dashboard_controller, which contains a def method for each dashboard pages. IE:
#dashboard/users
def users
#users = User.all
respond_to do |format|
format.html {render :layout => 'dashboard'}
end
end
the controller of the dashboard is at /controller but for views and assets I have put it in /folder/dashboard/
Here is 2 questions:
What is the best way to build the home website and dashboard ? Should I have a controller per page or a global controller where I have a method per pages ? (Which I find very convenient, less code).
How should I organize my routes to avoid to set a get "something/something" for each page ?
Or it is normal with RAILS that I have a route defined for each of my page ? I'm fairly new.
EDIT:
To clarify, the dashboard is built around an existing application with API that follow RESTFul Rails pattern:
resources :users
resources :routes
But the dashboard is not tied to any existing resources, it only do stats about those resources.
If you have custom controller action names, then yes, you'll need to define every route. If you use Restful routes, then you can define them easily as
resources :users
which will automatically create routes for actions: index, show, edit, update, create and destroy.
This might be helpful: http://guides.rubyonrails.org/routing.html
For your dashboard, which probably is bringing together a lot of resources, so they'll probably be custom methods. I'd suggest focusing on building your app by individual resource. Then, once you've defined them all, build your dashboard.
I agree with everything that other people have said here. You should definitely try to be more RESTful and create more routes like this:
resources :users
However, there is usually a controller that is not RESTful (usually called pages or static) that serves pages such as Privacy, About Us, etc, etc. For those routes, I usually do this:
['api', 'privacy', 'us'].each do |p|
get p, :controller => 'pages', :action => p
end
check this guide out if you haven't;
I think you haven't embraced the MVC concept of Rails.
For example, say you have "users". You should have users_controller.rb, users.rb (model), /views/users (view) under the app directory.
users_controller contains the index, show, create, etc default actions and your custom actions like stats
user.rb contains instance/static/helper methods
/views/users/ contains templates that corresponds to actions in the controller.
I am new to ruby, i would like to pass parameters in the url and receive it in controller.
I am expecting operation like
www.mysite.com/getuser/id/22
where getuser is the param name and 22 is its value.
Please provide me if there is any useful links that i can refer to.
Thanks in advance
Please read everything in the Rails Guide to Routing. There are two main cases there:
RESTful routes: only use GET, PUT, POST, DELETE. Rails maps that by using the method resources. resources :pages will lead to the following routes (and URLs) automatically:
sites GET /sites(.:format) {:action=>"index", :controller=>"sites"}
POST /sites(.:format) {:action=>"create", :controller=>"sites"}
new_site GET /sites/new(.:format) {:action=>"new", :controller=>"sites"}
edit_site GET /sites/:id/edit(.:format) {:action=>"edit", :controller=>"sites"}
site GET /sites/:id(.:format) {:action=>"show", :controller=>"sites"}
PUT /sites/:id(.:format) {:action=>"update", :controller=>"sites"}
DELETE /sites/:id(.:format) {:action=>"destroy", :controller=>"sites"}
Other routes: There is a rich set of methods you can use in your routes file to add additional routes. But keep in mind: If you just want to address a resource, it is better to stick to restful routes. A typical example is_ match ':controller(/:action(/:id))'. This allows URLs like:
localhost:3000/sites/help: controller == SitesController, action == help
localhost:3000/sites/search/something: controller == SitesController, action == search, parameter in params is something under the key id. So inside the action search, you will find params[:id] bound to "something".
In your config/routes.rb file you write:
resources :users
Then you create the controller:
rails g controller users
Inside your controller file you have something(contrived) there like :
def show
my_id_param = params[:id]
end
When you go to:
www.mysite.com/user/22
my_id_param will be 22
I think rails guides are quite good resource, just google for them, has ton of good info there.