what is the difference between resource and resources in rails routing
resource :geocoder
and
resources :posts
What is real difference between them ?
In essence, routing resources is when resources gives action abilities to a controller.
http://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use
If a pluralized resources is used as a way to handle generic requests on any item, then a singular resource is a way to work on the current item at hand.
So in other words, if I have a collection of Apples, to retrieve a specific apple, I'd have to tell the router "Apples" what apple to retrieve by sending the ID of the apple. If I already have one Apple, then an ID is not needed.
Notice the differences between the two by looking at what actions (or routes) they have:
resources: Index, new, create, show, edit, update, destroy
resource: new, create, show, edit, update, destroy
In your example:
The controller "geocoder" is a singular resource that you can use to edit, create, update, etc.
The controller "posts", is a plural resource that will handle incoming generic posts that you can index, edit, create.. etc
Singular Resources:
Sometimes, you have a resource that clients always look up without referencing an ID. For example, you would like /profile to always show the profile of the currently logged in user.
Or, Normally your currently logged-In user belongs to a single organization, so to goto his/her organization profile page there can be two routes
#1
/organizations/:id
#2
/organization #simply
Here, the later implementation makes more sense; isnot it? you get the organization object from association
# in organizations#show
#organization = current_user.organization
To define such singular resource you use resource method: Example
# in routes.rb
resource :organization
creates six different routes in your application, all mapping to the Organizations controller:
whereas, you define plural resources using resources method
resources :organizations
http://guides.rubyonrails.org/routing.html#singular-resources
Sometimes, you have a resource that clients always look up without
referencing an ID. For example, you would like /profile to always show
the profile of the currently logged in user. In this case, you can use
a singular resource to map /profile (rather than /profile/:id) to the
show action.
A good way to see it is that resource does not have an index action, since it's suppose to be just one.
i think just the index view.
also there have been reported issues with routing with the resource helper and form helpers. personally, i use the syntax:
resources :someresource, except: :index
in order to avoid the reported bugs.
Related
I have a nested resource as such:
resource :user, controller: :users do
# code ...
resources :profile, controller: :profiles, shallow: true do
# code ...
collection do
get :featured
end
end
end
The focus is the featured action of profiles.
The URL this generates is /user/profile/featured. I don't understand this because I specified shallow: true, yet it's still being nested under user/. I want the URL to be /profile/featured instead.
If I just do get :featured instead of putting it in a collection, I get /profile/:id/featured, which is also not what I want.
There are two types of routes within a given resource: collection routes (i.e. routes on the collection), and member routes (i.e. routes on individual records). When you specify that a nested route should be shallow, it only keeps routes nested that MUST be nested, and everything else is un-nested. Let's simplify your routes a smidge so we can talk through it better:
resources :users do
resources :profiles, shallow: true
end
If you take a look at the routes generated by that, you'll notice that the only profile-related routes nested under the user are:
GET /users/:user_id/profiles: Obtain a list of all profiles for this user
GET /users/:user_id/profiles/new: Render the page to create a new profile for this user
POST /users/:user_id/profiles: Create a new profile for this user
Everything else is no longer nested under users. Notice what all of these have in common: for this user. This comes back to what I said earlier: Rails only nests what it must. The user is an important part of the equation here, and there's no other way that it can be identified (without manual work on your part, anyway). However, once we have a record, we have a profile ID we can operate on. We no longer care about the user, and thus we don't need nested routes anymore.
In general, Rails expects that, since you've implied that profiles belong to users, it makes the most sense to only generate routes for operating on the collection within the scope of the user to which they belong. In other words, in most cases, you don't care about fetching the entire collection of profiles, you only care about the profiles for a particular user.
As a result, collection routes remain nested. On the other hand, for member routes we have a profile ID to work with, so they are not nested.
In your case, you're trying to do something a bit out of the above-described ordinary, so you'll need to create such routes yourself. Hopefully that explains the behavior you're seeing, though.
A final note, in case anyone notices: I used the plural resources here, where you actually used resource. It doesn't actually matter-- resource implies that there's a single user to operate upon when it sees a /user route, which is equivalent to the case with resources when it sees a /users/:user_id route. I used the plural form because I find it a little easier to understand.
To have more than one route on a course resource, we use resources :course. We use the singular resource for only one route like courses#new. Is it feasible to use resources :course even if I have one route? I figure it would be easier later on to add course routes if it is already plural. Is there a downside to making resource plural from the get go?
Singular resources like:
resource :course
generate only 6 routes instead of 7. So the plural index route is left. But the main reason for differing between singular/ plural resources is its expressiveness.
Sometimes, you have a resource that clients always look up without referencing an ID. For example, you would like /course to always show the current course. In this case, you can use a singular resource to map /course (rather than /course/:id) to the show action:
GET
/course/new
courses#new
return an HTML form for creating the course
POST
/course
courses#create
create the new course
GET
/course
courses#show
display the one and only course resource
GET
/course/edit
courses#edit
return an HTML form for editing the course
PATCH/PUT
/course
courses#update
update the one and only course resource
DELETE
/course
courses#destroy
delete the course resource
Also read Singularize resource routes, if it is singular!
Please consider this for your decision. So if the course resource is singular in its context choose singular resource, otherwise choose multiple resources.
I've been wondering if there is any better way to handle one-to-one relations with Rails.
I have a User model, which has_one Subscription. When the user is logged in, I get the subscription by retreiving current_user.subscription, so that finding subscriptions by id in URL is unncessary.
Right now, when user wants to update his subscription, he gets the url:
/subscription/3/?plan_id=2
But the subscription 3 is unncessary, and the other thing is I don't want to be showing the number of subscriptions (ids) to the user.
Whats would be a better solution for this? Would you guys bother with that?
Thanks
You could use resource :subscriptions (not resources). As described here (link)
the difference is, that resource doesn't create an index route (only if you say explicitly that you want one) and doesn't need IDs in the url
Quote from the linked answer:
At a high level, the intent of resource is to declare that only one of
these resources will ever exist. For example:
resource :profile, :only => [:edit, :update] As a user, I should only
be able to update my own profile. I should never be able to edit other
users' profiles, so there's no need for a URL scheme like
/users/1/profile/edit. Instead, I use /profile/edit, and the
controller knows to use the current user's ID rather than the ID
passed in the URL (since there is none).
That's why you don't get an index action with resource: there's only one resource, so > there's no sense in "listing" them.
I guess You have something like this defined in Your routes
resources :subscriptions
What You want is a collection level custom action which is defined like this:
resources :subscriptions do
get 'new_plan', on: :collection
end
Now You will need to add an action in You controller of the same name. And the link to get there will be: /subscription/new_plan?plan_id=2
Situation: I have a team model, a user model and a teamate model for the users of a team.
Say I want to have a view that contains the information of a team team/show
and that I wish (to simplify the user's experience) to add a list of the users, an add user to team and the possibility to remove a user from that team.
To be perfectly restful, I would need a controller (let's call it Teamates), it would handle the users of a team.
I would have all the CRUD needed.
Is it clean to have the team/show view call the teamates controller for the following actions: adduser, removeuser, listusers.
What I am trying to achieve is less clicks for the users.
In other words, I would like the user to be able to manage the users of a team from the team view instead if requireing him to navigate even further.
I don't think you need a controller for teamates.
And you really should not have adduser/removeuser/etc actions in your team controller!
You could set up your routes like that:
resources :teams do
scope :module => "team_scope" do
resources :users
end
end
Then you would have a UsersController in app/controllers/team_scope/users_controller.rb
To create a new user for a team, you would post to: /team/1-team-a/users and it would hit the create action in the UsersController above.
When you use scope in your routes, it does not change the route helpers like with namespace. The new action would just be accessible via new_team_user_path(#team).
Hum... so yeah, in this case I would have a TeamatesController, and maybe set up my routes like that:
resources :teams do
resources :teamates, :only => [] do
collection do
get :edit
put :update
end
end
end
And then you could edit the associations between a team and its players...
Your form would post the users id to team_teamates_path(team)...
But I'm really not sure it's the best way, I'd have to think about it. This is not really restful as well.
I'm working on a rails app and using a singular resource. However the controller name for the singular resource is plural.
Eg map.resource activity_report expectes the activity_reports_controller.
The explanation given in the rails 3 guide is: "... you might want to use the same controller for a singular route and a plural route..." That is a reasonable explanation, but what is the use case for using the same controller to handle a singular route and a plural route?
In a RESTful Rails application there is usually a mapping of one controller per RESTful resource. For example, let's say we wanted a controller to process user logins (/session) but also to provide a list of users who are currently logged in (/sessions). Logically we could put both of those responsibilities within a SessionsController:
class SessionsController < ApplicationController
# GET /sessions
# Display a list of logged in users
def index
...
end
# GET /session/new
# Display the login form
def new
...
end
# POST /session
# Authenticate a user
def create
...
end
end
An alternative would be to split the functionality for listing logged in users out into a separate administration controller.
You can use it.
class UsersController < Application
end
map.resource :user
map.resources :users
Another situation in which I can imagine using it would be, let's say (and this isn't necessarily the business model you'd want, but stay with me for a moment) you are going to make a site of film reviews, and film information. So, on the one hand you'd have the link to your list of the latest reviews be a plural resource route, something like this:
http://yoursite.com/reviews?count=5
So, in this case, you have a controller for the collection, right? But you're only going to review each movie once. So what if you wanted to provide an easy access to a movie's review?
http://yoursite.com/movies/pirates_of_the_carribean_2/review
Well, there's a nested single resource route, because a movie has_one review, right?