at https://www.codecademy.com/en/courses/learn-rails/lessons/start/exercises/start-views, the controll action is described as 'pages#home':
Well done! Now when a user visits http://localhost:8000/welcome, the route
get 'welcome' => 'pages#home'
will tell Rails to send this request to the Pages controller's home action.
but when I made the controller I did rails generate controller Pages which is uppercase.
pages_controller.rb:
class PagesController < ApplicationController
def home
end
end
Is the pages part of pages#home determined by the first part of pages_controller.rb, ignoring the _controller.rb end?
What happens if I change pages_controller.rb to renamedpages_controller.rb but leave the class name as PagesController?
thank you
Action Controller is the C in MVC. After routing has determined which controller to use for a request, your controller is responsible for making sense of the request and producing the appropriate output. Luckily, Action Controller does most of the groundwork for you and uses smart conventions to make this as straightforward as possible.
Controller Naming Convention
The naming convention of controllers in Rails favors pluralization of the last word in the controller's name, although it is not strictly required (e.g. ApplicationController). For example, ClientsController is preferable to ClientController, SiteAdminsController is preferable to SiteAdminController or SitesAdminsController, and so on.
Following this convention will allow you to use the default route generators (e.g. resources, etc) without needing to qualify each :path or :controller, and keeps URL and path helpers' usage consistent throughout your application. See Rails Guides.
When a request is made like: http://localhost:8000/welcome, it matches a route in the routes.rb file where the route is mapped to a controller and an action.
In your routes file, you have:
get 'welcome' => 'pages#home'
get 'welcome' part matches with the url .../welcome and map this request to pages#home where pages is the controller name and home is an action (a method defined in pages_controller). This is Rails convention to name the controllers like this: ControllerName_controller.rb. So, basically pages is your controller's name and the last _controllers is common to each and every controller in your Rails application.
What happens next is, this action of the controller do some work and talk to the model/database and build the required variables/data that will be passed to a view. According to Rails convention, there has to be a matching view file like: home.html.erb which will render the response to the browser.
There are other ways to render different partials and views in different ways, but if you follow the Rails convention, then it becomes very easy to understand and work with different Models, Views and Controllers in Rails. This is called: Convention Over Configuration.
When you follow the Rails convention for naming things, Rails does a lot of work and configuration for you for free to make your life easier.
When you have get 'welcome' => 'pages#home' in your routes file, then when a request: /welcome comes, it maps to pages_controller and it will look for the pages_controller.rb file under the app/controller/. If you rename this to something else, then the program will not find it as it expected and will throw you an error and your request will not be completed.
Your controller's name has to match with the class name of that controller, This is also a Rails convention. If you change any one of them, then you will get an error and your request will fail.
Yes. and #home is the "action" in PagesController
You get a uninitialized constant PagesController error
So, your controllers should always be in the form NameController defined in name_controller.rb, and actions as public methods in NameController.
Related
I am somewhat confused as to how to properly access an action in a rails controller that is NOT associated with one particular model. The routing file, by default, seems to be routing the action name to "id". So if I type, say, /user/login, I end up with an error that says: "Couldn't find User with 'id'= login"
What is the proper way to access arbitrary action names in rails?
Make a route for it, obviously. The request goes this way:
first it hits a route
from there it hits a controllers' action
[an action may invoke a model] (optional, but common)
controller specified a view and fetches data to render
view is sent back in response to a request
resource and resources might not be obvious about what they do. But in fact, they are shorthands to corresponding collections of routes used quite often, like this is what resources adds. And they're not monoliths, they can be customised to fit your needs. Providing options is just a start, you can provide a block to define your custom action routes for this resource like so:
resources :users do
get :login
end
This will add a /users/login route that maps to UsersController#login, following Rails' conventions.
See this guide for more details and don't forget to run rake routes to see what you have at the moment.
I have 2 questions:
I have a controller called homepage. I have a view called samplegraph in my homepage's view directory. I want to get the routing working correctly such that www.homepage.com/samplegraph takes me to the samplegraph page.
As far as I can tell, the route for it in routes.rb should be something like this:
GET 'homepage/samplegraph' => 'homepage#showgraph1'
If I'm understanding rails routing correctly, this statement routes GET requests to homepage/samplegraph to the homepage controller's showgraph1 action. At this point I'm not particularly sure what the showgraph1 action should be in order to render the view page(samplegraph). At the moment the action is simply empty. I don't really know what to put here.
Second question:
Also, while I was researching rails routing, I was looking into resource based routing. For my purposes, I don't need most of the stuff generated by that. One thing I am interested in is that invoking resource based routing automatically generates Paths for you via helpers(I think?).
How would I generate a Path for my route, such that I'd be able to use a link_to method to link various parts of the application together? Any help/comments would be greatly appreciated.
Firstly, if you want to get 'samplegraph' page rendered by hitting 'www.homepage.com/samplegraph', you will need to update your route.
Replace
get 'homepage/samplegraph' => 'homepage#showgraph1'
with
get '/samplegraph' => 'homepage#showgraph1'
Now in showgraph1 action of your homepage controller, you will need to render samplegraph view page at last line of the action.
render 'samplegraph'
As of you second question, just hit rake routes on your terminal from your app directory. It will show all routes with helpers which you can use with link_to. You will need to append _path to those routes while using with link_to
Like #RAJ said first of all you need to change your route to
get '/samplegraph' => 'homepage#showgraph1'
At this point I'm not particularly sure what the showgraph1 action should be in order to render the view page(samplegraph)
Rails doesn't care if your action is empty or not, it'll still render your actions view even if it's empty. Since your action is named showgraph1 so it'll make rails look for showgraph1.html.erb with path views/homepage/showgraph1.html.erb
To change this behavior you need to use render 'samplegraph' in your action
One thing I am interested in is that invoking resource based routing automatically generates Paths for you via helpers(I think?)
Rails generate path and url helpers for each route and it doesn't depend on how your routes are defined but you can customize your helper methods by specifying as: option
get 'homepage/samplegraph' => 'homepage#showgraph1', as: 'showgraph'
This will make your helper methods showgraph_path and showgraph_url
I am quite new to rails but i have searched a lot how to do this but it doesnt seem to work for me. Im trying to create a new view called request for my model called steppy_steps, so i created a new file in the views directory called request.html.rb, added this to my routes, match '/request' => 'pages#request', also tried get "steppy_tests/home", and lastly added (def request, end), to my Steppy_Tests_Controller.rb but when i check the url it gives me an error:Couldn't find SteppyTest with id=home
I cant figure out what to do any help would be great! Thanks in advance.
You should read up on the MVC programming pattern (which is what Rails is based on)
In order to make a view, you need to have the controller and model aspects in place too. I think you're doing this already, but to help you understand more, I'll outline below:
Views : Controller Actions
If you want to show a view from the steppy_steps controller, you need to first have a controller action set up to handle the request. You'd normally use a self-named controller for this (controller name steppy_steps), and have various actions for that
In your routes, you'll then "capture" the request to your steppy_steps controller like this:
#config/routes.rb
resources :steppy_steps
This will create a set of RESTful routes, which you can then translate into your controller, like this:
#app/controllers/steppy_steps_controller.rb
def index
#Index code
end
def show
#Show code
end
This will allow you to create a views directory which can contain the views for /views/steppy_steps/show.html.erb and /views/steppy_steps/index.html.erb
Routes Are Super Important
The error you're getting is caused by you sending /home to your view
The problem here is that if you're using a route which has an in-built id param (the show action routes have this), then Rails will look for the extra params after the URL
To fix this, you'll have to provide more of your code, but I also believe you'd be better understanding the fundamentals of Rails a little more
Adding Routes
You can add routes & views as you wish
If you're looking to add a requests route / view, I'd do this:
#config/routes.rb
resources :steppy_steps do
collection do
get :requests
end
end
This will allow you to create /steppy_steps/requests
I'm Learning Rails. Lots of the conventions make great sense. The convention for code that maps to controller actions is odd:
//code url controller action
tweets_path /tweets/ def index
tweet /tweet/ID def show
new_tweet_path /tweets/new def new
edit_tweet_path(tweet) /tweets/ID/edit def edit
Why aren't the automatically generated method helpers done in the same symmetrical way as the controller actions? eg:
//code
tweet_index
tweet_show(tweet)
tweet_new
tweet_edit(tweet)
I'm so new I'm sure there's a perfectly good reason, I just don't know it yet :)
There are two asymmetries here.
The first is plural vs. singular route helpers. Why are some helpers tweets_* helpers while others are tweet_* helpers?
The answer is that some resource routes are member routes and others are collection routes. Member routes have to do with an instance of a resource and collection routes have to do with all instances of a resource as a group (unless the resource is singular in which case there are no collection routes). The index action is a collection route and the show action is a member route.
You can declare your own member and collection routes like this:
# routes.rb
resources :tweets do
member do
get :duplicate
end
collection do
get :summarize
end
end
This will create two helpers in addition to the standard ones. Note that Rails will create route helpers that are appropriately singular or plural.
a summarize_tweets_path helper that does not take a parameter
a duplicate_tweet_path helper that does
Official docs are here.
The second asymmetry is that the action is left out of the helper for many of the built-in resource actions. I suppose this could have been for brevity, but I don't really know.
Edit
After thinking about it, the action name was dropped because there is path overloading in Rails and REST. The '/tweet/:id' path could be the show, update, or delete action depending on the HTTP verb. Basically, the path tells you what you are operating on but not what action to take.
The helper methods are generated in a way that makes them more readable by making them more like parts of sentences. Saying 'Create a link to a new tweet' sounds better than 'Create a link to a tweet new'. It helps to keep this in mind as well when naming any custom actions, using names that fit sentences makes it easier to comprehend and remember since this is how we learn to speak.
One reason for it not being symmetrical is that the mappings depends on the HTTP action. For example, a GET to /tweets map to the index action, but a POST to /tweets maps to the create action.
I have product with a foreign collection_id key
I want to pass an id to a controller.
To do so i have the following routes for my controller :
controller :magasin do
get "magasin" => "magasin#index"
end
The only view in my controller is magasin/index.html.erb
The link to magasin is link_to collection.nom, magasin_path(collection)
This kind of syntax usually works in controllers with models. Here my link is : http://localhost:3000/magasin.2 instead of http://localhost:3000/magasin/2
Later on i will need to call the same view with product_kind_id instead of collection_id and i will add sort by name/price ....
How can i have the ID as a normal argument (/:id)instead of a type(.id)?
A popular URL schema to follow is RESTful routing. Rails has this built-in and will set it up for you if you initialize your resource via rails generate scaffold Magasin nom:string.
If you put resources :magasins in your routing file, it will route /magasins to MagasinsController#index and /magasins/1 to MagasinsController#show with params[:id] set to "1". It will also set up a few other routes that will be useful in the future but for now will just raise an action not found exception.
You don't want to use the dot as an argument delimiter, since Rails places what comes after the dot in the request.format method or just in params[:format] (ordinarily accessed through the respond_to method that comes with the generated scaffolds). Save that dot for later when you are working on delivering alternative display formats like XML and JSON.
I realize I've said a lot in a small space, so feel free to ask any follow up questions once you've consulted the Rails Guide on the issue, and I'll be very glad to help!