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.
Related
I have been following this guide to make a Ruby on Rails web app:
http://guides.rubyonrails.org/getting_started.html
It is supposed to be a quiz where people answer questions.
I have made :questions a resource. However, the guide mentions a page on its website to be able to create and delete its resource articles. Obviously this makes no sense with quiz questions as I just want to create them once and after that no more can be created or deleted. However, there is no mention of this in the guide?
If you don't want to be able to create/update/destroy your questions through controller, you can exclude these restful routes with :except, or specify the routes you need with :only which is more obvious(take a look at the routing guide):
resources :questions, only: [:index, :show]
This will create following routes:
GET /questions questions#index
GET /questions/:id questions#show
To fill your database with questions, use seeds(which are described in AR migrations guide). Put your questions creation related code into db/seeds.rb file and run rake db:seed afterwards.
You should specify in your routes to only :show the questions.
Do something like this in your routes:
resources :questions, only: [:show]
So as much I understand, you want to create resources and data on your own but don't want other users to be able to create or delete a resource, right?
let's start with the basics:
In MVC, the model/resource is the main representation of the entities.
The routes file indicate what routes are available at the first place
for each entity to which HTML requests can be sent. It also matches the route with a respective controller action. The controller
provides a gateway for users to interact with your application, takes
a request from them, take actions needed( issue SQL commands to create, show, delete from the database etc) and give a suitable response at the end.
So, suppose you want users to create a new resource on your server. First, you provide a route on which they can send a request. Then, you give them a create new resource button in your view through which they can interact. That button will use the route, match it with a controller action and send a request to that controller method. Depending on what is inside the controller action, the controller then creates the resource and redirect the user with a 302 with a notification.
Now, suppose you don't want a request to go through. What will you do?
You will firstly not create a route on which a request can be sent. You will also not create a controller action on which request can be received.
That's the use case in your scenario.
Since you don't want users to be able to send a request to the server to create the resource:
Don't provide the routes for them to send any such HTML request
Don't provide any controller which will receive such request
And obviously, don't provide any button in the view to take that action.
Now, the question would be: Then how will I create the resource?
You have three options:
Use a seed file: You can use a seed file where you add all the data you want. This tutorial and many other resources on the web can help you out. http://www.xyzpub.com/en/ruby-on-rails/3.2/seed_rb.html
Use rails console: Give create commands: Question.create(:name => "hello", :description => "How you doing!"). See the link here: https://apidock.com/rails/ActiveRecord/Base/create/class
If you are a beginner, you need to work a little more before trying this: Create authorized users and what actions they can take. You can also create an admin dashboard and provide all actions to admin users using activeadmin gem.
This blog explains the process: http://www.onceaday.today/subjects/1/posts/9 3
Finally, as you do need to show all the questions: create only show route, match it with a controller action, write the method in the controller action which issues a SQL command to get all the resource from the database and give the respective show view the data it can render.
Hope it helps you out!
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'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.
So, I'm trying to access other actions in my controller, and it assums I want "show" every time, when I really just want... the action I just had in my URL.
this is in my routes:
map.resources :attachments
And when I do
domain/attachments/any_action?params
I get this error:
ActionController::UnknownAction (No action responded to show. Actions: {list of actions}
Using rails 2.3.8
I think I know what you are getting at.
Yes show is assumed for singular uses and index for plural.
This is a convention.
Much of the power / magic in rails comes from "convention over configuration" and this is one of them. Yes it could have been /attachment/show/ or /attachments/index but why not just eliminate the show and index if these are the most common and have them available as defaults and that is what rails does.
Now, as for actions not being available, lets look at that. First of all, right off the bat, please do a rake routes at the command line and see what you get. Also please indicate which actions you are trying. The restful setup "resources" will make 7 actions available:- index, show, new, create, edit, update and destroy, but not "any action"
The rule in Rails is first route matched, first route served.
Because you define a resource, it will consider everything like domain/attachments/whatever to be show action for the whatever stuff.
So two choices here:
define your other routes and declare them before the resource
nest your other routes inside the resource (I don't know how to do that in Rails 2.x)
Just as you figure out the route when the browser hits the webpage in Rails, how would you resolve it on the server side?
For example I want to return a URL to a RESTful resource called Bookmark in an API call and want to return the 'show' action of it, and I know that:
Bookmark id: 12
Then I want to resolve it to a string:
'/bookmarks/edit/12'
so that I can get this from my Model for example.
How would I go about doing this?
Thanks!
Pretty much everywhere in the views/controllers you can use route helpers to DRY up route references.
In models, you'll need to explicitly call the route helper like so.
Rails.application.routes.url_helpers.edit_bookmark_path(id) # => '/bookmarks/12/edit'
When using the default resourceful route generator method in routes.rb like
resource :bookmarks
I'm not sure I understand - your server is the thing that's making all of those routes work - the client's browser isn't figuring out what the route is - you application is doing it.
The paths to your resources are available as helper methods at all times (at least within the controllers, and views). As such, you should return the string as the body of a response in one of your actions, in the controller that's handling your API calls.
Check your rake routes on the command line, and you'll see a list of them. In the case of your example above, it would likely be called edit_bookmark_path(12)