What is a "resource" in Rails? - ruby-on-rails

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

Related

What is a good naming convention for Rails custom controller actions regarding formulation (noun vs verb)?

When defining new actions in controllers I often find myself asking how should I formulate the name of the action correctly. Rails default CRUD actions all seem to follow the pattern of verb (new, create, edit, update, destroy, index) but is it a bad habit to use a noun? For ex. payment_history?
I found a lot of information describing the naming conventions for different files and classes and regarding the proper syntax but none about controller#actions from formulation part.
EDIT: I am asking about custom-defined actions not renaming the Rails default CRUD actions.
In my opinion, important thing about choosing name of the action should not be based on whether it is a noun or a verb, the name of the action should describe the behavior of the action itself, whether it calculates/gets/loads/renders/etc something. So that, when another person (or you after a long time) reads the code, he/she should be able to easily understand what is this action used for and what is expected result from this action.
Otherwise you could just name it is as * whatever * since ruby doesn't prohibit you to do so.
As example we can take a look at payment_history and list_payment_history. If I am reading the code and see action named list_payment_history, I understand that it lists the history, even without looking at the code I understand the purpose of the action. However if I see payment_history, I can only understand that it has something to do with history, not the exact meaning, does it show history, or may be sort history, archive history... no concrete understanding towards the purpose of the action.
Assuming you're following the conventional RESTful methodology, it is going to be easiest to follow the convention of index, show, new/create, edit/update and destroy. That is, unless you have a well-grounded reason not to, but then you ought to be able to justify to yourself and possible other developers why the default action names are not sufficient.
Using the default method names, you get a lot of the routing etc. stuff "for free", as Rails assumes you're following the convention. Also, do note that things that might not immediately sound like "resources" can often easily be modeled as such, e.g. your example "payment_history" may well be a subresource of another resource (a User?), in which case you'd have a singular nested route such as GET /users/{user_id}/payment_history. This route would then call PaymentHistoryController#show, as demonstrated in the Rails guide section on singular resources.
I don't know that it matters so much, though in general I think you're looking for a verb. Your models are typically nouns, and controllers define actions.
Controllers In rails acoording to my reading and experience
Controller class names use CamelCase and have Controller as a suffix. The Controller suffix is always singular. The name of the resource is usually plural.
Controller actions use snake_case and usually match the standard route names Rails defines (index, show, new, create, edit, update, delete).
Controller files go in app/controllers/#{resource_name}_controller.rb.
Example:
# app/controllers/bigfoot_sightings_controller.rb
BigfootSightingsController < ApplicationController
def index
# ...
end
def show
# ...
end
# etc
end
# app/controllers/profiles_controller.rb
ProfilesController < ApplicationController
def show
# ...
end
# etc
end

rails, implementing a master detail yet staying RESTful

Say that I have a Customers and an Orders tables, where each Customer may have many Orders.
Since in rails we are encouraged to represent these resources in a RESTful style, each of our resources, will respond to the following actions
index
show
edit
new
create
delete
So far, it all is very fair and plain. But now say that each time i open the show page of my Customer, i want to show a detail table containing all his/her orders.
This is a very common need, but doesn't this "unclean" the correctness of restful approach?
Is there some workaround, like "mashing" the two resources at a "view level", leaving them separate from the rest point of view?
Rails' default conventions ensure a RESTful application, and the only way this might become non-restful would be if you used custom-names on the routes, in which case you would have you add an extra bit of code to specify the HTTP method.
So, to accomplish what you're suggesting, at the view level, you may have something like this:
app/views/customers/show.html.erb
....
<% if customer.orders.any? %> #the orders method is provided on `customer` by defining the `has_many` and `belong_to` associations
<%= render #orders $>
And you would make sure to define #orders in the show action of the customers_controller.rb file.
This not only is RESTful, but also works within Rails' default conventions.
Those actions you list are not what makes something RESTful. There are a bunch of characteristics an application must have to be considered RESTful. Some of these characteristics are:
it is thought of as a repository of resources
resources are identified by a URI
there is a uniform interface for interacting with resources - the HTTP verbs of GET, POST, PUT, DELETE, etc.
Rails takes care of receiving HTTP requests and calling your application's functionality, regardless of whether it is RESTful in nature or not, through routing. Rails routing takes those HTTP verbs I mentioned, in combination with a URI, and determines which controller to call. By default Rails follows the RESTful paradigm, and by convention will map verb/URI combinations to those actions you listed - but the actions themselves, and the fact that they are lumped into a single controller, are not part of REST - they are just the rails convention.
In fact, the rails default routing maps 4 different resources to that single controller and its actions:
/customers // the list of all customers, GET/POST -> index/create
/customers/new // a form for creating a customer, GET -> new
/customers/{id} // a single customer, GET/PUT/DELETE -> show/update/destroy
/customers/{id}/edit // a form for editing a customer, GET -> edit
Resources can contain sub-resources, and Rails completely supports that. A sub-resource might be:
/customers/{id}/orders // the list of all orders for a particular customer
Another key part of REST is that it supports a resource having different representations, whether that is HTML, XML, JSON, etc. Clients use HTTP headers to convey what representation they are passing into the app (using the Content-Type header) and (usually) what they will accept in response (using the Accept header).
Its up to the application to determine what a resource representation looks like. Typically a resource will either be "thin" or "fat". A "thin" resource is one that simply has links to its sub-resources and further calls must be made to get them. A "fat" resource will contain the fully-fleshed out sub-resources it contains. Typically with an HTML representation, an application will return some form of "fat" resource. There is nothing non-RESTful about this - and is exactly what you are describing you want for your application.
So that was my long way of saying "don't be afraid of not being RESTful by displaying sub-resources - it's perfectly OK" :-)

Opinions on RESTful route for DELETEing of nested resources?

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.

Ruby on Rails - differentiating plural vs singular resource in a REST API

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

Why do I need to work harder to make my Rails application fit into a RESTful architecture?

I started a Rails project recently and decided to use RESTful controllers. I created controllers for my key entities (such as Country) and added index, new, edit, create, show, update and delete. I added my map.resources :country to my routes file and life was good.
After development progressed a little, I started to encounter problems. I sometimes needed extra actions in my controller. First there was the search action that returned the options for my fancy autocompleting search box. Then came the need to display the countries in two different ways in different places in the application (the data displayed was different too, so it wasn't just two views) - I added the index_full action. Then I wanted to show a country by name in the URL, not by id so I added the show_by_name action.
What do you do when you need actions beyond the standard index, new, edit, create, show, update, delete in a RESTful controller in Rails? Do I need to add (and maintain) manual routes in the routes.rb file (which is a pain), do they go in a different controller, do I become unRESTful or am I missing something fundamental?
I guess I am asking, do I need to work harder and add actions into my routes.rb file for the privilege of being RESTful? If I wasn't using map.resources to add the REST goodies, the standard :controller/:action, :controller/:action/:id routes would handle pretty much everything automatically.
I would treat search as a special case of index. Both actions return a collection of resources. The request parameters should specify things like page, limit, sort order, and search query.
For example:
/resources/index # normal index
/resources/index?query=foo # search for 'foo'
And in resources_controller:
before_filter :do_some_preprocessing_on_parameters
def index
#resources = Resource.find_by_param(#preprocessed_params)
end
As for index_full and search_by_name, you might look at splitting your current controller into two. There's a smell about what you've described.
Having said that, you're absolutely right that there's no point in forcing your app to user restful routes when it doesn't deliver anything over /:controller/:action/:id. To make the decision, look how frequently you're using the restful resource route helpers in forms and links. If you're not using them, I wouldn't bother with it.
If I go beyond the standard CRUD actions with my models, I normally just add the methods as required. Searching is something I add to many controllers, but not every one, so I add it and maintain the routes normally:
map.resources :events, :collection => { :search => :get }
Moving these actions to an entirely separate controller might keep some of your controllers RESTful, but I find that keeping them in context is far more useful.
REST does not specify that you can't have additional views. No real world application is going to be able use only the supplied actions; this is why you can add your own actions.
REST is about being able to make stateless calls to the server. Your search action is stateless each time as the data so far is supplied back, correct? Your alternate display action is also stateless, just a different view.
As to if they should be manual routes or a new controller, that depends on how distinct the activity is. Your alternate view, if it provides a full set of CRUD (create, read, update, delete) operations would do well to be in a new controller. If you only have an alternate view to the data, I would just add an alternate view action.
In other words, it doesn't sound like your application is failing to be RESTful, it is more an issue of realizing that the automatically generated feature set is a starting point, not a conclusion.
In my opinion they may have gone a bit off the rails here. What happened to DRY?
I'm just getting back into Rails not having done much development with it since beta and I'm still waiting for the light-bulb to come on here. I'm still giving it a chance but if it hasn't happened for me by the end of my current project I'll probably just drop-back to the old standard routes and define the methods as I actually need them for the next one.
I won't go on to explain more about REST since I think that has been answered in this question, however I will talk a little bit about the default route.
My main problem with the default route is that if you have multiple sites using the same Rails app it can look horrible.
For example there may be controllers that you don't want people to be able to see on one app:
http://example1.somesite.com/example_2/foo/bar/1
compare this to
/:controller/:action/:id
This would go to the controller example_2/foo, action bar and id 1
I consider this to be the main flaw of Rails' default route and this is something that RESTful routes (with subdomain extensions) or only named routes (map.connect 'foo' ... ) can fix.
To remain RESTful in your design, you need to rethink what you call a resource.
In your example a show action for a search controller, (search resource) is the direction to remain restful.
In mine, I have a dashboard controller (show) and controllers for single fields of in-place ecditors (show and update)

Resources