I'm looking to do what Basecamp does essentially, having my URIs be like this:
www.example.com/:user_id/
www.example.com/:user_id/projects/12314
Where you can only access that which is scoped under your user_id.
My ideas so far are:
To nest all other resources under users
To use a scope scope: ":user_id" do
And then just passing current_user whenever I create a path.
What's the best way to go about this?
Best approach is to implement nested routing(the one you are thinking of) to handle the above scenario, in which resources will be nested under parent. But you also need to think about the individual existence of resources whether they exists or not without user as sometimes few routes can exists without user so for that you also need to define them seperately in routes.rb.
as reference: http://guides.rubyonrails.org/routing.html#nested-resources
as example: http://blog.8thcolor.com/en/2011/08/nested-resources-with-independent-views-in-ruby-on-rails/
Related
This is my current route configuration:
resources :organizations, path: ''
resources :users, path: ''
I want to create a similar experience to what GitHub does. When using GitHub, you can access organization and user profile pages by entering "https://github.com/#{username}"
Now, the routes configuration above leads to the obvious problem that accessing organizations works fine while accessing a user fails because Rails only considers the organizations route and does not attempt to find a user.
Note: I am using friendly id to use usernames in my URL's and also made sure that usernames are unique across both ActiveRecord classes.
How do I do what I want to do?
You can create additional controller like PageOwnerController and pass request to it:
get ':page_owner_nick', to: 'page_owners#show', as: :page_owner
In show action you can manually find desired record by params[:page_owner_nick].
Advice: it looks like you have many a lot of similar logic between users and organizations - take a look on STI. Using STI allow you to write common code easier, but at the same time to separate different logic.
Given a typical nested resource of a photo with comments, the route to create a comment would look something like:
POST /photos/{photo_id}/comments
Now, for deleting the comment, would you still use a "nested" route? ex:
DELETE /photos/{photo_id}/comments/{comment_id}
or
DELETE /comments/{comment_id}
The pro of the nested route is that it mirrors the creation URL and doesn't require any additional entries in routes.rb. The pro of using a top-level URL is that you technically don't need the photo_id to get the comment to delete.
Thoughts?
How you model the comments resource depends heavily how you see the resource comments.
In case a comment could exist without a photo and could be associated with 0 to N resources like photo then you should model your comments like this
GET /comments/{comment_id}
DELETE /comments/{comment_id}
PUT /comments/
POST /comments/{comment_id}/associations/photo/{photo_id}
In case a comment is always associated with a resource and cannot exist without being associated with a resource then you should stick with
POST /photos/{photo_id}/comments
DELETE /photos/{photo_id}/comments/{comment_id}
I guess the confusion how to model the comment is driven by the database model where every comment gets a unique id that is unique among all comments and not just unique in a photo_id and comment_id combined key. I suggest not to let the database model leak to the resource model and go for a model that fits your conceptional understanding of the resource.
Can you GET this?
GET /comments/{comment_id}
I guess not. But if you can't GET a resource, you can't DELETE it, too.
So only your second option is RESTful.
Personally, I'm just using nested route for delete, means i used:
DELETE /photos/{photo_id}/comments/{comment_id}
to delete comments of a photo. If i use:
DELETE /comments/{comment_id}
so i have to create one more route for this? I don't find any reasons to create a separate route for delete, I think it's not necessary. The nested resources have create url and path for us, and they are follow convention, why don't we use them? I just want to keep it simple and will not do extra work for things already have.
Objective:
Be able to nest a resource, like records inside of users so that I can access /users/1/records to see all of the first users records. But I would also like to see /records to see all of the records ( or the new ones, or something like that ).
Problem
So I know I am missing something somewhere because that cannot be the way to do it. I know I can have like a static page or some other route for that, but I don't think that is very rails-y.
I would have users, so a user would see their page with their records, but also be able to browse records, so I assumed I would need a more general route for that.
Question
What is the appropriate way to browse a nested resource?
PS I have looked at things like this question, which almost address the problem, but deals with a static landing page for non logged in users, this is not what I am looking for.
Not sure how to handle this route later in controllers (never tried), but something like this should work:
resources :records
resources :users do
resources :records
end
I think you'll need to do something in records's index controller to check if its called for some user or not.
UPD: Ok, checked it. Check for params[:user_id] in your index controller.
Dumb question but I have some lingering confusion of what, exactly, a "resource" is in Rails. The term is used everywhere but I get a funny feeling it might be being used rather loosely. It's referenced in the model, the controller and, quite literally, in routes.rb.
Is it the specific route? For example, map.resources maps the 7 RESTful "resources". So an example of one resource would be the call to, say, the index action of a particular class's controller?!?
Is it a reference to the whole page/object being retrieved? or perhaps, more narrowly, a database table? or the row being retreived?
Is it something else?
Anyway, hopefully someone can set me straight...
Any object that you want users to be able to access via URI and perform CRUD (or some subset thereof) operations on can be thought of as a resource. In the Rails sense, it is generally a database table which is represented by a model, and acted on through a controller.
For example, you might have a User resource (with a users table in your DB). This is represented by a User model, is mapped to users_controller with map.resources :users (which then generates routes like /users (a collection of User resources) and /users/1 (a specific User resource).
You act upon those resources by using the appropriate HTTP method when making calls to those resources. POST to the resource collection (/users) creates a new record; GET retrieves a list of resources (/users) or a specific user (/users/1). PUT updates a specific user (/users/1/), and DELETE destroys that user. The URLs are the same, but the result (and controller action) may be different based on the HTTP verb. The idea, though is that /users/1 always means "I'm interacting with the User that has ID #1", regardless of the action.
Here's a good article discussing how most developers think that "Resource" is synonomous with the database table, the argument, I guess, being that mapping to the resource is mapping the controller to that database table (or, with ActiveResource, to another REST url).
Basically, I think a "resource" is "persisted data." map.resources maps the 7 RESTful actions to a particular suite of persisted data.
But I haven't thought about it too much in depth. Good question!
I think they probably mean it in the general web sense, i.e., Resource (Web):
the referent of any Uniform Resource Identifier
I don't think it has anything to do with database tables.
open your model folder, that is a hint of what resources you have!
example: users, pictures, comments...
A lot of people here say that resources refer to the database tables you have. It might be true sometimes but not necessarily true always. I could give you a lot of examples where you don't have a corresponding table in your database for a particular resource. Hence asssociating it with tables is rather wrong.
I would define a resource as a route which maps to related requests. So instead of declaring separate routes for the actions you want to do you can simply declare them using a resourceful route.In Rails, a resourceful route provides a mapping between HTTP requests and URLs to controller actions.
So say you define resources :users in config/routes.rb. You can now use a number of helpers to the controllers in your application like edit_user_path which returns users/edit .
Here's a good link: https://api.rubyonrails.org/v5.2.1/classes/ActionDispatch/Routing/Mapper/Resources.html
Which basically says: Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your index, show, new, edit, create, update and destroy actions, a resourceful route declares them in a single line of code:
resources :photos
I'm working on building the URLs for my REST API before I begin writing any code. Rails REST magic is fantastic, but I'm slightly bothered the formatting of a URL such as:
http://myproject/projects/5
where Project is my resource and 5 is the project_id. I think if a user is looking to retrieve all of their projects, then a respective HTTP GET http://myproject/projects makes sense. However if they're looking to retrieve information on a singular resource, such as a project, then it makes sense to have http://myproject/project/5 vs http://myproject/projects/5. Is it best to avoid this headache, or do some of you share a similar concern and even better - have a working solution?
Rails (3) has a lot of conventions when it comes to singular vs plural. For example, model classes are always singular (Person), while the corresponding tables are always plural (people). (For example, Person.all maps to select * from people.)
For routes, there's a concept of a singular resource as well as a plural resource. So if you did resource :account then you would get paths like /account for the default path or /account/edit for a path to a form to edit the account. (Note that Rails uses /account with a PUT method to actually update the account. /account/edit is a form to edit the account, which is a separate resource from the account itself.) If you did resources :people, however, then you would get paths like /people, /people/1, and /people/1/edit. The paths themselves indicate whether there can only be one instance of a given type of resource, or whether there can be multiple instances distinguished by some type of identifier.
I agree, go with the flow. Consider how the URL forms a hierarchy.
The root of your website is where you start to access anything.
/projects/ narrows it down to only projects, not anything else. From projects you can do lots of things, /list, /index/, /export, etc... the /id limits things even further.
At each / the scope of what do becomes narrower, and I think it makes sense.
Further programming is all about arbitrary rules. Indexs starting at 1 vs 0, and so on. Anyone working with your urls will sort things out in short order.
There are cases where a singular path to a resource is helpful. If your resource ids are non-numeric user defined names then routing clashes are possible. Example:
/applications/new --> create a new application or show user's application named new?
In this situation you can choose to limit the user input to avoid the clash, or, this can be worked around by overwriting the default Rails 3 behavior:
class ActionDispatch::Routing::Mapper
module Resources
RESOURCE_OPTIONS << :singular_resource
class Resource
def member_scope
#options[:singular_resource] ? "#{singular}/:id" : "#{path}/:id"
end
def nested_scope
#options[:singular_resource] ? "#{singular}/:#{singular}_id" : "#{path}/:#{singular}_id"
end
end
end
end
Then when specifying a new resource route:
resources :applications, :singular_resource => true
Which will generate the routes:
GET /applications
GET /applications/new
POST /applications
GET /application/:id
GET /application/:id/edit
PUT /application/:id
DELETE /application/:id