Based on my current understanding, if I had to describe how the various components of a rails app work together to respond to requests, I would say the following:
1) Routes determine which request URLs map to which controller methods.
2) Controller methods obtain information from the models and pass that information (in the form of global variables) to corresponding view templates.
3) View templates use the data stored in the global variables to construct the final response.
In the above explanation, the relationships between several components are clear and undeniable; namely:
1) routes and controller methods
2) controller methods and view templates
In fact, the above relationships are 1-to-1.
However, the relationship of the model classes to their adjacent component type (i.e. controllers) is not as clear. Yes, the controllers retrieve information from the models, but consider the following:
1) A controller does not necessarily need to retrieve information from a model, as would be the case for a static website.
2) A controller could retrieve information from multiple model classes.
Therefore, would it be accurate to say that models exist slightly more separately from the other components? Would it be accurate to say that, taken together, the model classes make up the back-end of the back-end of your application, whereas the other components (i.e. routes, controller methods, and view templates) compose a tightly-coupled, linear mechanism wherein the controllers dip into the model classes as necessary? And more specifically, would it be accurate to say that, at least in the context of how the rails components actually fit together, there is no natural relationship between any given controller and any given model (e.g. UserController and User)?
Yes, I know rails comes with the "resources" keyword for use in the routes file to generates RESTful routes and that things are often done in a RESTful way in rails. You could say that rails lends itself to the development of RESTful web applications. And in the context of a RESTful application, the model and controller are implicitly related to each other. But that's a description of the REST architectural style. I'm asking about rails. It seems to me that in rails itself, models are only related to controllers to the extent that the model is used in the implementation of the controller's methods - and because code organization in software is arbitrary, those relationships are arbitrary.
I'm thinking about these things because I want to add a way for users to view their own profiles. I already have a User model and a controller and views for displaying information about users. The profile page would display information from the User model, but I don't want to use the same controller or views for the user's own profile as I do for displaying information about other users. So, I plan to create a new controller and views for the profile, but use the User model to retrieve the information that gets displayed. It's an arbitrary decision, much like other arbitrary decisions made when building an app. But it wouldn't be a valid decision if for some reason models and controllers were supposed to remain tightly coupled (e.g. 1-to-1) in rails.
Can anyone confirm or refute what I'm saying?
For a great explanation of MVC, check out Jeff Atwood's post: http://blog.codinghorror.com/understanding-model-view-controller/
Now as for your app, one controller is just fine for displaying User's profile pages. What you should do to ensure security is that for the UsersController#show action (profile page) you should validate that it is the current user, otherwise redirect, or show error message, or show the editable page, etc.
#user = User.find(params[:id])
if current_user != #user
render :show
else
render :self_profile
end
Another method you could use is:
#user = User.find(params[:id])
if current_user != #user
#authenticated_user = true
end
render :show
Then in your view template, you can have a conditional:
<% if #authenticated_user %>
#Edit button here, takes you to the settings page
<% else %>
#Follow button here
<% end %>
current_user should be a helper_method defined in the application controller.
Creating independent controllers is fine. You could also create a route that points to your UsersController#show action and handle the case when the user is viewing his or her own profile there.
In a non-trivial app you will end up with controllers that do not match resources and models that do not have a controller and that's ok.
In your case, maybe all you want is a different route (ex: www.example.com/me), that doesn't mean the action logic can't be in the UsersController. In the end, it's all about keeping similar logic in one place so that it's easier to maintain.
Related
I'm new to MVC pattern and Sails. From my understanding, it seems like I should create a controller for each model. A controller is like one page.
So, if I want create a page containing product category, product list and user authentication, there are 3 models in my page. How should I structure the controllers?
You don't have create separate controllers for each model.
Controllers handle the request from the client and return views, JSON, etc.
You may be being influenced by how sails documentation explains things due to their blueprints.
Mvc does not require a 1 to 1 of controller to model. Your controller should take care of massing the data and rules needed to show your view or a group of different views. A controller may have a link to a group of your functionality e.g. user management where you handle registrations, login, forgotten credentials etc. This may require a few different models and not just your user model. It may also display a number of different views too.
Sails.js comes with blueprints enabled which means a user model will have create,update,find,findone etc against a user model. Infact sails doesnt need a controller in this instance but you could make one to over ride logic or add additional logic. There is however nothing stopping you calling a user.find method in the user controller as well as a pets.find. Just think of the controller as the conductor telling and calling everything to fire and bringing this information together to push into a view or number of views.
What we usually see in framework documentations are simple blog-like applications where each page is related to only one model and one controller.
How to deal with the most common case where a single page have to display information from different models?
Example:
A social network home page that shows:
Recent user posts
Recent users
News from the admins
Most played games
Is this supposed to be handled by a single controller that loads all this information from the different models and send it to a view that is potentially broken down into partials / elements?
Someone said in another question that I could create something like a HomePageController for pages like this. What if all that information should be displayed in the sidebar for all pages on the site, how do I handle that?
Typically, you'll collect all the different kinds of data and pass it to the view together:
MVC frameworks generally provide some way to map request URLs (e.g. /offers?id=5) to controllers (or their methods).
Let's assume that you want to display some data on your homepage.
To do this, you'll first define mapping from URL /home to some particular controller, let's say HomePageController.
Using your example data, you'll have something like this in your controller (in method that will handle request):
model.add(dao.getRecentUserPosts());
model.add(dao.getRecentUsers());
model.add(dao.getNewsFromAdmins());
model.add(dao.getMostPlayedGames());
render("viewName", model);
Upon request to some adress mapped to this specific controller, you will get different kinds of data from your Data Access Object (dao), and the add them to your model.
Once model is filled with data, you can pass it to a view ( = render view with this model), and in view you'll display it any way you want to.
I hope that basic flow is now clear to you.
Referring to #BeK's answer:
handling requests that take longer will always need an individual approach. You may choose to load this part asynchronously, you may (and probably will) try to cache as much as you can.
Loading the sidebar:
most of MVC frameworks provide some kind of 'base template' for your view.
That means you can define one part of view (e.g siderbar or footer) that is displayed on every page, and in particular controllers you only care about the dynamic parts. Those solutions are flexible enough to satisfy most of the typical needs.
There are a lot of options depending on what are you displaying in that sidebar - is it static or dynamic? what can be cached? etc.
There are several options here. It really depends on what kind of data you are loading. If one of the data requests takes a long time the view will not be displayed until all the data is gathered. If you break the view down in partials and let them load async, the user will have a better UX. In this way you can have the separate controllers/controller methods, complying with patterns like SRP.
If you want all the data to be displayed in the sidebar of every page, than maybe one controller taking care of it will be an easier solution, but again I would suggest take a look at the data you are loading and especially the time it takes to load all the data. Hope this answers your question or sets you on the right path.
alternate approach to follow SRP is using MVC child actions.
create many models and controller. each controller responsible for its own business logic
eg.
PostsController
NewsController
GamesController
HomeController
starting from HomeController that render the HomePage.cshtml
<div>#Html.Partial("Login.cshtml", Model.CurrentUser)</div>
<div>
<hgroup>
<h2>what's new</h2>
</hgroup>
<div>#Html.Action("WhatNew", "News")</div>
<div>#Html.Action("RecentlyPosted", "Posts")</div>
</div>
<aside>
<h2>Games</h2>
<div>#Html.Action("MostPlayed", "Games")</div>
</aside>
you may fetch list of many controller/actions name as string in HomeController then render multiple child actions in main page.
I've learned that you should set up the controller-class in a MVC-OOD as a use case, from top to bottom in only one method that run the MVC-classes.
Is it OK to use different methods in one controller to get more control and better overview?
Let's say you wanna run a controller that will display a login form (getting the html etc from the View). And the same controller will also display a log-out button IF the user is NOT logged in.
This could be done with a single method in the controller, but using two methods seems better. One method to call if you want the login form, and one to call if you want to log-out button.
(just an example)
So, what does the pros say. Should each controller contain one "use case" method only, or could it be several?
TL;DR -- you have misunderstood the MVC design pattern and are doing it wrong.
Controllers are not responsible for rendering the interface, nor for presentation logic. Controllers do not display anything. Instead, each controller's method deals with different user's request. It extracts the data from said request and passes it to model layer and the associated view.
Decisions about what and how to display are in purview of views. Views contain the presentation logic in MVC pattern. In the context of web applications, views create the response. They can compose a from from multiple templates or just send a single HTTP header.
Controllers can signal the associated view by passing some specific values of the request to that view, but most of the decisions in the view are based on information that the view requested from different services in the model layer.
A Controller's methods are based on what type of requests a user can send. For example in a authentication form it might be: GET /login and/or POST /login.
Its important to remember two things with MVC, firstly, its an Object-Oriented Architecture, and secondly, It should be used for separating concerns.
Separation of Concerns is related to Abstraction, It is to aid us in understanding the section of code at hand. The Model and View are both collections/domains of related objects. Each object is fully complete and relevant to its domain.
You will find objects with types such as Buttons, Images, Text Inputs etc inside your View, and you will find business related objects (User, Account, Profile etc) within your Model.
The collection of objects inside your Model don't tend to do much, They require logic to wire the objects together. (Or simply delegate simple single object requests to the correct object)
The Controller provides the interface into your Model, and contains the business logic related to the Model and the interactions between the Model objects. You will have a single Controller for your Model, and the Controller will have multiple methods which will align with your use-cases.
I've done a fair amount of work on MVC on the web, and we're learning about it in my OOP class. I'm seeing some differences, and I can't tell whether that's because the Web's version of the MVC pattern is different than the traditional one, or whether I misunderstood it.
From my understanding, The model (your flat files, RDBMS', etc) is a generic data-housing object. The View (Browser, HTML, etc) is what the user interacts with, and the controller mediates between the users actions and the data. The controller is the most domain-specific part, and it manages the views, tells the model what it needs, and tells the views what to display.
In class, we have the Views matching what I just described, the Model contains a list of the views so that it can update them when the data changes, and the controller simply maps the user's actions to calls to the model and to specific objects (which may themselves, ask the model to update the views). What ends up happening is that most of the business logic is in the model, and it's tied very heavily to the simulation or application that is being written, while the Controller is reduced to a mapping tool between commands and methods.
What are your thoughts on this?
In a non-web interface the controller handles the inputs from things like the keyboard and mouse, choosing which views to render and what changes to make in the model based on those inputs. The view and model can be more closely related because the view can register callbacks directly with the model entities to be notified of changes and thus be updated based on changes to the model directly instead of being updated by the controller.
In the web world, views are necessarily more decoupled from the model. It must act through the controller actions because it has no direct access (after being rendered and delivered to the browser) to the model. The controller takes a larger role in this environment even though the only "input" it has to deal with are browser requests. In a sense, the coupling that used to occur with the view in non-web MVC is transferred to the controller acting on its behalf. Since there are no callbacks from the model to respond to (let's forget about "push" technologies for now), more business code is incorporated into the controller since it's the natural place to model business processes, though perhaps not validation.
In my understanding controllers in the web MVC pattern are just bridges between Models and Views, they simply grab the data from the Model and pass it on to the View. The Model and the View and independent and never talk to each other.
In MVC, where is the correct place to put authorization code?
The controller?
The Model?
In the view?
All over the place?
I vote for putting it where it makes sense. Most of my authorization stuff is handled via decorating controller actions (or even some controllers) with the AuthorizeAttribute -- or an attribute derived from it. In a few cases -- like my menus -- I've resorted to putting the authorization check in the view code itself, rather than calculating it in each controller and passing flags down in ViewData. There are a few instances where certain aspects of the model are only available to particular roles and in those cases I've resorted to extending the model with methods that can take the current user and roles and do the check there.
I think authorization is a cross-cutting concern. Should be in one place - an aspect that can be declaratively applied where it's needed.
The Controller!
Your View should only handle user interface and display
Your Model should represent the data in your system.
Your Controller should handle the logic of how the system works.
Authorising a user involves taking the credentials provided from the View, checking them against some sort of authorisation list in the model and then performing a check.
This is done in the controller:
Get user credentials from View
if(compare with user list in model returns match)
authorise users
else
refuse access
If you have to choose between M, V or c, the C is the correct place. But, I recommend an architecture where your app is all contained in libraries and the UI is just a thin veneer. You end up calling down the stack from the Controller, but the code is not in the controller.
In MVC, the Model is just a model, or a "dumb data object", if you will. It is designed to hold state, and should not dictate behavior. The View is for the user to interact with and is also "dumb"; the view handles UI. The controller is where behavior sits, or is the entry point into behavior in the case where the app logic is in libraries. Make sense?
Model.
Controller is just for switching through different ways. View is just for... viewing.
So you should make all authorization codes in the Model layer. Ideally, everything will work just fine. If not, then the controller will take the user to the proper login box.