I know its a question which has been asked hundreds of times before but I'm stressing over the naming scheme I adopt for Controllers in my ASP.Net MVC application.
Say, for example, I have a model called User of which I have the singular ability to view, update and delete. Likewise, I also have a collection of Users which I can search upon giving many results.
As the routing is of the form of {controller}/{action}/{parameter} then my 'English' head thinks that a URL of:
http://localhost/users/view/123 is not correct as the URL relates to a single product whereas:
http://localhost/user/view/123 is correct, as the user is viewing a single product
And likewise, with Product and Products:
http://localhost/product/edit/P123456
http://localhost/products/?searchQuery
This seems to make more sense (well, to me anyway) and thus means that I have to implement two Controllers for each Model but at least this means I know that the singular controller deals with a single entity whereas the plural version deals with multiple entities:
UserController -> Add, Edit, View, Delete
UsersController -> Find, Delete
I guess the only fly in the ointment is when I come across an entity which is the same singularly as plural but within the scope of my project, this could be quite a rare thing.
I'm sorry if this is mindless babble however I'd appreciate some input from users who've gone through this before.
It does not matter. Users are normally not navigation through your site by typing urls, but by clicking links, buttons, menu's, ....
Related
I'm trying to better understand the Rails workflow, specifically RCAV in relation to MVC. I know that MVC is the typical structure of a Rails app and that RCAV is the standard order of building various components of the app, however, I'm a little confused about the correlation between the two.
For example, I'm assuming the routes in RCAV are what link the models with views and controller in MVC. Is this correct?
I'm also guessing that the controller and view in RCAV are the same as the controller and view in MVC and simply represent the order in which you build them. Is this correct as well?
What I'm really stuck on is the Action part of RCAV - does this represent the Model component of MVC?
Sorry if my question doesn't make sense, just trying to get a better hang of the standard Rails workflow and the order in which various components of an app are typically built. I wish it were a little more distilled i.e. "first build Model, then Views, then Controller" but this whole separate RCAV thing is confusing me a little.
To your title question, no.
To elaborate, it's kind of confusing to map out RCAV (the sequence) against MVC (the framework), but I'll see if I can clarify. It's worth noting that the concepts themselves are not as complex as they seem, it's just confusing to explain.
RCAV
(Route-Controller-Action-View)
Routes are defined in config/routes.rb. You may think of them as the coupling between an HTTP Request and a Method (a specific type of method called an Action). On the one side it defines a path (ex. "/login") and one of the HTTP verbs (ex. "GET"), and says that whenever that type of request is made to that location, to perform the appropriate action. On the other side, an action is given in the form of the name of its controller (ex. "sessions"), and the name of the method itself (ex. "new").
Controllers receive the request according to the routes (so following the above example, if a user navigated to www.example.com/login, they would wind up in the sessions controller, which would be housed in app/controllers/sessions_controller.rb). The Controller may perform a number of functions prior to (and following) the action, in the form of callbacks. Callbacks are arguably a more advanced concept than what you need to understand right now, they are an important step (and the reason I explain RCAV as "Route >> Controller >> Action >> View", not as "Route >> Controller-Action >> View").
Actions are public methods in the Controller. Again, by our above example, you'll be hitting a method named "new" in the sessions_controller when a user navigates to www.example.com/login. Actions may perform any variety of functions, and there is often interaction with the model here (for instance, you may have a session model in app/models/sessions.rb with a method named "logout", and perhaps the first thing you do when you hit the login page is ensure the user is currently logged out by calling Session.logout. This is a poor design, but a decent example). Your action must "return" in one way or another. Assuming your action is meant to be consumed by a user directly through their browser (as opposed to as, say, a JSON or XML service), you will either render a view now, or redirect_to another action.
Views are, dare I say, the "end result" of the action. If nothing is specified, the above example will end by rendering "app/views/sessions/new.html.erb" for the user (Rails defaults to rendering the view whose path matches the controller and action, but as referenced above you could name something different). In this file you will also potentially make reference to the model associated with sessions (but this time inside of ERB tags, to be compiled into HTML).
MVC
(Model-View-Controller)
Models are classes tied, generally, to tables in a database. They contain validations for their fields, class methods, and instance methods. Say your database keeps track of sessions. Then you could potentially grab a list of sessions by calling Session.all anywhere in your application. You'd probably use an action in the Sessions controller to save this list to an instance variable (maybe #sessions), which could in turn be accessed in its appropriate view (<% #sessions.each do |s| %> ... <% end %>).
Views are essentially the web pages. They can bring along their own styles and scripts, and exist in the form of HTML files with embedded ruby. They are the end point of request made to your site (unless you're hitting a service which returns something like JSON or XML instead).
Controllers contain all the actions a user may access, often prepare variables via methods from the models, and generally drop the user into a view.
In Summation
A user accesses a route. The route drops them into a specific action within a controller. The controller (in the form of callbacks) and the action (on its own) prepare data from the model (via instance variables) to be consumed by the view. The view is then rendered into the users browser.
This is a simplification, but in the most standard cases, this is how the MVC framework (and rails, specifically) functions.
Is there a general rule of thumb to how controllers should be organised?
Should Controllers only be created if they are linked to a domain model?
For instance if I have a 'Product' model, I would have a ProductController, which would have actions such as 'GetProductDetails' etc...
But what about things that don't have an actual model, such as searching for products, and returning multiple products on a page?
Since the Product model is the underlying model for all these interactions, should this functionality be included into the ProductController and have actions for searching and displaying multiple products, or should another be created for Search?
If you follow the pattern used by the scaffolding used in visual studio then yes you end up with one controller per entity so a product controller would have a actions that returned a list, a single product and an action for posting update to. In addition you might have additional search actions and any other product related actions. Which is just state and reinforce infer-on's answer.
However the reason why you would do this is that it means your code is easier to maintain - if you're looking for code to do with products you have one controller class to look in. You're also adhering to the principle of separation of concerns each controller is only concerned with one type of entity.
Further to this if your app grows much larger and you use an IoC / dependency injection pattern then you only need to inject one repository or business service per controller that is a search controller that offers methods to search for products and customers would need services or repositories for customer and products but a request might only be a customer search so the creation of the products repository was pointless hence you get inefficient and overly complex code. There are patterns to solve this issue but they involve even more code so to avoid this and to keep it simple stick to one root entity one controller.
You should manage every action which involve same resource with same controller, and you should implement that solution in accord with Richardson Maturity Model
A model (developed by Leonard Richardson) that breaks down the
principal elements of a REST approach into three steps. These
introduce resources, http verbs, and hypermedia controls.
so your API will be something like this:
/api/products GET Gets full list of all categories
/api/products/123 GET Gets the details for a single category
/api/products PUT Replaces the entire list of categories with
the one given
/api/products/123 PUT Update the specified category
/api/products POST Creates a new category
/api/products DELETE Deletes all categories
/api/products/123 DELETE Deletes the specified category
Disclaimer: I really spent time thinking about names of models and variables. If you also do, this question is for you.
I have a Rails project which contains two models: User and Project.
They are connected by the model ProjectsUser, which is a connection model in a many-to-many relationship. This model also holds the role of a user in the given project, along with other attributes such as tier and departments. So this is a has_many :through relationship.
Given this scenario, here is everything that always bothered me on all my rails projects since I started developing on it:
Should I use a ProjectsUserController or better add the relevant actions on UserController and ProjectController? At some point, I want to assign users to a project, or even changing the role of a user in a given project. Is it a better practice to leave those actions on the connection controller, or use the model controllers?
Should I write a method to get the role of a user for a given project? This is basically if I should have a method User#role_for(project) or not. Since this method basically is getting the information from the projects_user object it could make more sense to always let this explicity on the code, since most of the times I'll have the project and the user, but not the projects_user. Is this line of thinking correct, or maybe the problem is that I'm should have more project_user on my code than I really do? Are there good caveats for this?
Should I try to rename my table to a non-standard name if it is not obvious? Ok, I got that if I have the models User and NewsSite I should use has_many :subscriptions, but the thing is that naming those models in real life cases are usually harder, by my experience. When the name ends up not being that obvious (for exemple, in my case, maybe project_participation as #wonderingtomato suggested) is for the best, or in those cases it is better to fall back to the ProjectsUser approach?
One extra cookie for pointing beautiful open source Rails code, or by book indications that might help with my kind of questions.
I would use a specific controller. Even if now the interaction sounds simple, you can't know if in the future you'll need to add more advanced features.
I've been handling these kind of relationships in several projects, and using a controller for the join model has always paid off.
You can structure it this way, for example:
index should expect a params[:project_id], so that you can display only the index of users for a specific project.
create is where you add new users, that is where you create new join models.
update is to modify a value on an existing join model, for example when you want to update the role of a user in a project.
destroy is where you remove users from the project, that is where you delete the corresponding join models.
You might not need a show and edit actions, if you decide to manage everything in the index view.
Also, I'd suggest to choose a different name. Rails relies heavily on naming conventions, and projects_users is the default name for the join_table you would use with a has_and_belongs_to_many association. In theory you can use it for an independent model (and a has_many through:), but it's not immediately clear and you might break something. In addiction, it will confuse the hell out of any new programmer that could join the project in the future (personal experience).
What about calling the model something like project_participation?
If you haven't built a lot of functionality yet, and don't have yet that table in production, changing it now will save you a lot of headaches in the future.
update
1) I stand by what I said earlier: your join model is a full fledged record, it holds state, can be fetched, modified (by the user) and destroyed.
A dedicated controller is the way to go. Also, this controller should handle all the operations that modify the join model, that is that alter its properties.
2) You can define User#role_for(project), just remember that it should properly handle the situation where the user is not participating to the project.
You can also make it explicit with something like:
#user.project_participations.where(project_id: #project.id).first.try(:role)
# or...
ProjectParticipation.find_by(project_id: #project.id, user_id: #user.id).try(:role)
But I'd say that encapsulating this logic in a method (on one of the two models) would be better.
3) You are already using a non standard name for your table. What I mean is that it's the default name for a different kind of association (has_and_belongs_to_many), not the one you are using (has_many through:).
Ask yourself this: is the table backing an actual model? If yes, that model represents something in the real world, and thus should have an appropriate name. If, on the other hand, the table is not backing a model (e.g. it's a join table), then you should combine the names of the tables (models) it's joining.
In my mind, REST doesn't always have to map directly to DB records. A conceptual resource here is the association of Projects to Users. Implementation would be different depending on your persistence layer, but a RESTful API would be standard.
Convention over Configuration in Rails is a great helper, but it isn't necessarily applicable to every case 100% of the way through the stack. There doesn't need to be a 1-to-1 mapping between controllers, models, and their respective names. At the app-level, particularly, I want my routes/controllers to represent the public view of the API, not the internal implementation details of the persistence and domain layers.
You might have a UserProjectsController which you can perform CRUD on to add/remove project associations to users, and it will do the appropriate record manipulation without being overly bound to the DB implementation. Note the naming, where the route might be /user/:id/projects, so it's clear you are manipulating not Users or Projects, but their associations.
I think thinking about this sort of thing (both before and after the fact) is what leads to better designs.
I too start with the model and think about the application structurally. The next step in my oppinion is to build the user interface to make sense based on what makes it easy and useful for the user (spending more effort on things that matter more). So if it makes sense for the user to separately edit the ProjectsUser objects then the ProjectsUsersController is the way to go. More likely editing the join model objects as part of the Project (or User depending on the structure of you app) will be a better fit for the user. In that case using a nested form and editing via the controller (and model) that's the main model referenced by the form is better. The controller really lives to serve the UI, so decisions about it should be dependent on the UI.
Yes, if it makes your code simpler or more readable. If you use role more than once I suspect it will.
I would actually name that model something like Member, or ProjectMember (or Membership). It defines a relationship between a user and a project, so its name should reflect what relationship that is. In the occasions where such a name is too unwieldly or too hard to define then falling back to something like ProjectUser is reasonable (but not ProjectsUser). But I definitely like finding a more meaningful name when possible.
I have two questions on how the MVC works. I'm pretty sure I should add several resources, but I'm just coming to this conclusion and wanted to ask first to get a better understanding.
First question:
I have two models, user and subject. Users can enter subjects into the database. For each subject there are 5 data entry forms (Baseline, 3month, 6month,...) that are about 100-200 questions each (The relationship would be each subject has 1 of each data entry form). Should each data entry form be a new resource?
Second Question:
Lets say I want to randomize a few subjects into a group:
From the view, the user enters the amount of subjects to be randomized into a group, as well as the group name to be assigned. The form tag specifies an action I created, just for this function, called randomize.
From the controller, randomize uses the params sent from the view to query the database, and then to update each record to reflect the group. Instead of creating a new action for the randomize function, should I create a new resource for it? And as a side note, should any of these calculations be done in the model (other than defining the variables)?
Thank you for your time. Any help would be greatly appreciated. I am officially over-whelmed by all of the information I'm learning about this...but I feel that I'm really close to actually understanding the MVC.
I'll answer your second question first.
You should be creating controllers to handle CRUD tasks for resources. In this question you ask about creating a "Group". Regardless of whether this is an actual resource, or just a modification to a collection of other resources, you have the concept of creating a "Group", probably reading/updating a "group" and certainly deleting one.
Based on this, I would rather have a RandomGroup controller which I can call using a standard REST interface, rather than some #randomize action stuffed in the side of another controller.
As for your first question ... maybe, maybe not.
It really depends on whether an data entry form has any business logic of its own. If it doesn't then there's no harm it being part of a large object. But if your tests and code start to become too complex within the Subject model you may want to split it out into multiple models or at least multiple modules included into that model.
Perhaps you could consider that "Baseline", "3month", "6month" are all the same ... aside from their lead time. Perhaps that is a model in itself, and Subject could has_many :forms ??
Food for thought.
I'm brand new to MVC and, as a learning exercise, I'm trying to re-write an old application as an ASP.NET MVC application. I'm a little unclear about some conventions which the question Action Naming Conventions only partially covers.
Lets say I have two controllers: JobController and ClientController. Both of the controllers are going to have identical actions: List, Details, New, Update, and Delete.
Should the views for these actions be named identically to the action? In this case the List action for JobController should have a view named "List.aspx" as opposed to something like "JobList.aspx".
The reason this question came to my mind was that I was unsure if its appropriate to have multiple views with the same name (such as "List.aspx"). This will get more and more relavent as I continue adding controllers as pretty much every business object in my system will require a "List.aspx" of some sort.
They won't really have the same name. If it were important to give all our files different names why would we want folders? You actually have a Job/List.aspx and a Client/List.aspx.