The other day I stumbled on Sandi Metz's rules, and one of them reads
When a call comes into your Rails controller, you can only instantiate one object to do whatever it is that needs to be done.
Still pretty new to Rails, but I always thought that my controller methods had some smell in them, and this confirmed it. I have a dashboard view for a parent model that displays information about their children (a different model) and the children's challenges(another model), all with different controllers. Here is an example of one of our controller methods.
def dash
#parent = current_user
#children = #parent.children
#completed_challenges = #parent.assigned_challenges.where("parent_id =?", #parent.id).where("completed =?", true)
#validated_challenges = #parent.assigned_challenges.where("parent_id =?", #parent.id).where("validated =?", true)
#enabled_rewards = #parent.enabled_rewards.where("parent_id =?", #parent.id)
end
I was wondering if I could send multiple requests to get all of these objects from their respective controllers as opposed to lumping them all in one request. I know I can do this with Ajax, but is there a way just doing multiple http requests when the page is loading?
I appreciate the help!
The answer is NO.
AJAX was built specifically for that purpose, to overcome the short-comings of multiple http requests. Plus multiple http requests while page load is frowned upon because of the performance slump. It might seem lucrative path for a small project, but when it scales, you will definitely run into huge holes.
Though I am not a big fan of it, but following the beaten path can save you a lot of effort in this case. :)
The recommended approach is using the Facade Pattern. A perfect example of how to handle this is provided by Thoughtbot in the "Only instantiate one object in the controller" section of this blog post:
http://robots.thoughtbot.com/sandi-metz-rules-for-developers
When a call comes into your Rails controller, you can only instantiate one object to do whatever it is that needs to be done.
I see the usefulness of this rule, but I think you can interepret it in a slightly different way. When you load a controller, you do want it doing as little as possible. This is a given.
In your case, though, you seem to have a lot of different bits of data to load. Besides looking ugly, you'll see that the code also tends to get bigger and bigger as your dashboard supports more and more metrics. You don't really want to be in a situation where the number of lines of code increases proportionally with the amount of data an application shows.
Instead, send one object - a dictionary of all the data that you need to show. And I'd suggest moving the construction of that dictionary off to a model (or better still, a service) that builds it up (possibly based on configuration of some sort). The controller should just be fetching that object from somewhere and sending it back in the correct format.
Related
Until now, in my MVC application, I've been using the Model mainly just to access the database, and very little else. I've always looked on the Controller as the true brains of the operation. But I'm not sure if I've been correctly utilizing the MVC model.
For example, assume a database of financial transactions (order number, order items, amount, customer info, etc.). Now, assume there is a function to process a .csv file, and return it as an array, to be inserted into the database of transactions.
I've placed my .csv parse function in my Controller, then the controller passes the parsed information to a function in the Model to be inserted. However, strictly speaking, should the .csv parsing function be included in the Model instead?
EDIT: For clarity's sake, I specifically am using CodeIgniter, however the question does pertain to MVC structure in general.
The internet is full of discussion about what is true MVC. This answer is from the perspective of the CodeIgniter (CI) implementation of MVC. Read the official line here.
As it says on the linked page "CodeIgniter has a fairly loose approach to MVC...". Which, IMO, means there aren't any truly wrong ways to do things. That said, the MVC pattern is a pretty good way to achieve Separation of Concerns (SoC) (defined here). CI will allow you to follow the MVC pattern while, as the linked documentation page says, "...enabling you to work in a way that makes the most sense to you."
Models need not be restricted to database functions. (Though if that makes sense to you, then by all means, do it.) Many CI developers put all kinds of "business logic" in Models. Often this logic could just as easily reside in a custom library. I've often had cases where that "business logic" is so trivial it makes perfect sense to have it in a Controller. So, strictly speaking - there really isn't any strictly speaking.
In your case, and as one of the comments suggests, it might make sense to put the CSV functionality into a library (a.k.a. service). That makes it easy to use in multiple places - either Controller or Model.
Ultimately you want to keep any given block of code relevant to, and only to, the task at hand. Hopefully this can be done in a way that keeps the code DRY (Don't Repeat Yourself). It's up to you to determine how to achieve the desired end result.
You get to decide what the terms Model, View, and Controller mean.
As a general rule MVC is popular because it supports separation of concerns, which is a core tenet of SOLID programming. Speaking generically (different flavors support/ recommend different implementations), your model holds your data (and often metadata for how to validate or parse), your view renders your data, and your controller manages the flow of your data (this is also usually where security and validation occur).
In most systems, the Single Responsibility Principle would suggest that while business logic must occur at the controller level, it shouldn't actually occur in the controller class. Typically, business logic is done in a service, usually injected into the controller. The controller invokes the service with data from the model, gets a result that goes into the model (or a different model), and invokes the view to render it.
So in answer to your question, following "best practices" (and I'll put that in quotes because there's a lot of opinions out there and it's not a black and white proposition), your controller should not be processing and parsing data, and neither should your model; it should be invoking the service that processes and parses the data, then returning the results of aforementioned invocation.
Now... is it necessary to do that in a service? No. You may find it more appropriate, given the size and complexity of your application (i.e. small and not requiring regular maintenance and updates) to take some shortcuts and put the business logic into the controller or the model; it's not like it won't work. If you are following or intend to follow the intent of the Separation of Concerns and SOLID principles, however (and it's a good idea on larger, more complex projects), it's best to refactor that out.
Back to the old concept of decomposing the project logic as Models and Business Logic and the Data Access Layer.
Models was the very thin layer to represent the objects
Business Logic layer was for validations and calling the methods and for processing the data
Data Access Layer for connecting the database and to provide the OR relation
in the MVC, and taking asp.net/tutorials as reference:
Models : to store all the object structure
View: is like an engine to display the data was sent from the controller ( you can think about the view as the xsl file of the xml which is models in this case)
Controller: the place where you call the methods and to execute the processes.
usually you can extend the models to support the validations
finally, in my opinion and based on my experience, most of the sensitive processes that take some execution time, I code it on the sql server side for better performance, and easy to update the procedures in case if any rule was injected or some adjustments was required, all mentioned can be done without rebuilding your application.
I hope my answer gives you some hints and to help you
If your CSV processing is used in more than one place, you can use a CI library to store the processing function. Or you can create a CSV model to store the processing function. That is up to you. I would initially code this in the controller, then if needed again elsewhere, that is when I would factor it out into a library.
Traditionally, models interact with the database, controllers deal with the incoming request, how to process it, what view to respond with. That leaves a layer of business logic (for instance your CSV processing) which I would put in a library, but many would put in its own model.
There is no hard rule about this. MVC, however it was initially proposed, is a loose term interpreted differently in different environments.
Personally, with CI, I use thin controllers, fat models that also contain business logic, and processing logic like CSV parsing I would put in a library, for ease of reuse between projects.
I have gone through a number of videos and tutorials for understanding the difference between Model And Controller.
So what i understood is like controller is the medium between our view and Model , it captures the action performed on the UI and calls the appropriate model class, receives back the model object from the model class and send it to the view given by the view resolver.
Now my question is why do we make the controller to send the request to a model , why do we even need a different class(model). Can't we do the same thing in controller itself ?
It is easier to test and maintain / change / exchange.
The general idea behind MVC is so that you have different modules of your app each with their own function. This way you get less coupling and higher cohesion - coupling refers to classes connected so tightly that, if you decide to change one single variable in one single class you would have to go through your code and check everywhere for exceptions/bugs etc. Cohesion on the other hand refers to having smaller portions of code in separate classes, which depend on nothing else, thus when you change them you can be sure nothing else breaks.
Of course, this can not be explained in a few lines. The best thing you can do is to start writing code, some basic app and see the how it goes.
Really what you say you can do, but it is a bad practice, the MVC is made to separate the layers of development, thus to make it neater develop for all, it must meet a standard for good understanding and management not only but you Developer ...
I have this idea of generating an array of user-links that will depend on user-roles.
The user can be a student or an admin.
What I have in mind is use a foreach loop to generate a list of links that is only available for certain users.
My problem is, I created a helper class called Navigation, but I am so certain that I MUST NOT hard-code the links in there, instead I want that helper class to just read an object sent from somewhere, and then will return the desired navigation array to a page.
Follow up questions, where do you think should i keep the links that will only be available for students, for admins. Should i just keep them in a text-file?
or if it is possible to create a controller that passes an array of links, for example
a method in nav_controller class -> studentLinks(){} that will send an array of links to the helper class, the the helper class will then send it to the view..
Sorry if I'm quite crazy at explaining. Do you have any related resources?
From your description it seems that you are building some education-related system. It would make sense to create implementation in such way, that you can later expand the project. Seems reasonable to expect addition of "lectors" as a role later.
Then again .. I am not sure how extensive your knowledge about MVC design pattern is.
That said, in this situation I would consider two ways to solve this:
View requests current user's status from model layer and, based on the response, requests additional data. Then view uses either admin or user templates and creates the response.
You can either hardcode the specific navigation items in the templates, from which you build the response, or the lit of available navigation items can be a part of the additional information that you requested from model layer.
The downside for this method is, that every time you need, when you need to add another group, you will have to rewrite some (if not all) view classes.
Wrap the structures from model layer in a containment object (the basis of implementation available in this post), which would let you restrict, what data is returned.
When using this approach, the views aways request all the available information from model layer, but some of it will return null, in which case the template would not be applied. To implement this, the list of available navigation items would have to be provided by model layer.
P.S. As you might have noticed from this description, view is not a template and model is not a class.
It really depends on what you're already using and the scale of your project. If you're using a db - stick it there. If you're using xml/json/yaml/whatever - store it in a file with corresponding format. If you have neither - hardcode it. What I mean - avoid using multiple technologies to store data. Also, if the links won't be updated frequently and the users won't be able to customize them I'd hardcode them. There's no point in creating something very complex for the sake of dynamics if the app will be mostly static.
Note that this question doesn't quite fit in stackoverflow. programmers.stackexchange.com would probably be a better fit
If a view is served from a controller is it ok to pass data generated in that view via post and pass it straight to a model or do I need go back through the controller that served the view and call the model from the controller?
In CodeIgniter views get their data from the controller, which demultiplexes / validates parameters and retrieves the appropriate data from the model(s). It's important that:
Views are output. Views are not coupled with the models directly, as they define the HTML/XML/JSON/CSS (either pages, logical parts of pages, or other fragments of output data like APIs and resources). This means you do not call models from views in CI.
Controllers are proxies. Controllers and models do not produce output. Controllers take the GET and POST requests and make the calls needed for a view to print the result, often checking the parameters and multiplexing multiple model calls to get all of the appropriate data.
Models get and put data. Models should return their data in an agnostic format: either as data objects of the model, or as more generic (but consistent) hashes of data. The cleaner the returned model data, the less coupling you will find between your views and models (and the more you will be able to reuse model pieces).
In CodeIgniter there are a few places where you may find overlap:
JavaScript often ends up related to views (and may do things like validation, normally a controller task). You can improve this by moving Javascript out of the views (works well for larger pieces, less well for smaller bits).
In PHP, returning hashes (key/value arrays) is easier than returning objects (less code, but reduced type safety). This is often a source of coupling.
Shared output stuff often finds its way into controllers (you can avoid this by moving it into CI helper libraries).
The goal is for your views to be unaware of your models, except that they receive data from them that meets a particular specification. Controllers just get and put (they neither generate HTML output, nor access the data directly), and models are mostly SQL or other forms of getting data and stuffing it into something structured.
Speaking in an MVC agnostic approach I would say that the View going back to the Model is the correct approach. Purist may state always going back to the Controller.
A comment from here...
The model manages the behavior and
data of the application domain,
responds to requests for information
about its state (usually from the
view), and responds to instructions to
change state (usually from the
controller).
The phrases "usually" are key. Patterns are for manageability and maintainability downstream to some degree. Sometimes patterns are a hindrance to accomplishing the goal in a maintainable and manageable manner and are sometimes overused.
I would gather that going either route would be fine in this instance (small scale)...but it is also about how you are approaching the problem on an application wide scale.
Yes, you submit form data to controller functions. That function then processes the data and calls a view.
If you try it any other way, you'll end up in code hell.
One function can handle the original display of the form and the submission of that form.
Simply check if the form has been submitted, if so, process it's data, else display the form.
function login(){
if($this->input->post('submitted')==1){
//process the form data
}else{
//show the form
}
}
Question number three in my quest to properly understand MVC before I implement it:
I have two cases in mind:
The primary application
window needs to launch the
preferences window. (One View
invoking another View.)
The primary Model for an application
needs to access a property
in the preferences Model. (One Model
accessing another Model.)
These questions are related in that they both involve communication across Model-View-Controller triplets, a topic that I haven't found much discussion of in my Googling.
The obvious way to fix this is to wrap everything in a top-level "application" object that handles transactions between Models and allows Controllers to invoke one another's methods. I have seen this implemented, but I'm not convinced its a good idea. I can also see possibilities involving Controllers observing more than one Model and responding to more than one View, but this seems like its going to become very cluttered and difficult to follow.
Suggestions on how best to implement this sort of cross-talk? I feel like its a very obvious question, but I've been unable to find a well-documented solution.
On a broader note, if anyone has a link that shows typical approaches to these sorts of MVC issues, I would love to see it. I haven't had much luck finding solid, non-trivial references. Examples in Python would be lovely, but I'll gladly read anything.
Edit 1:
I see some pretty interesting things being said below and in general no-one seems to have a problem with the approach I've described. It is already almost a lazy form of the FrontController design that Vincent is describing. I certainly don't foresee any problems in implementing that pattern, however, it doesn't seem that anyone has really addressed the question in regards to communication amongst Models. All the answers seem to be addressing communication among objects in a single Model. I'm more interested in maintaining separate Models for separate components of the application, so that I'm not stuffing fifty state properties into a single Model class. Should I be maintaining them as sub-Models instead?
With respect to (1), views don't invoke other views. They invoke controller actions that may result in other views being rendered. In your case, the primary application window contains a user interface element (button, link) that invokes a controller action to display the preferences window.
With respect to (3), model components certainly could be related to one another. This isn't unexpected nor to be avoided, necessarily. For instance your Customer model may have an associated set of Orders. It would be perfectly natural to access the customer's orders via a method in the Customer class.
You might want to take a look at the MVC page on wikipedia for an overview.
You may want to consider looking up the Front Controller design pattern.
The Front Controller pattern defines a single component that is responsible for processing application requests. A front controller centralizes functions such as view selection, security, and templating, and applies them consistently across all pages or views. Consequently, when the behavior of these functions need to change, only a small part of the application needs to be changed: the controller and its helper classes.
This way all requests from the view goes to the FrontController who then decides which specific action (controller) to invoke. Sometimes, it could forward straight to another view as in your first case.
There is no problem with multiple objects in the model talking to each other. In fact that will be very common. The way I see it, all the objects in the Model act like one component to represent the data and operations on the data.
This article might help. And this one.
Model does not mean a single model object. The model is the subset of the entirety of your domain model which is directly related to the controller actions and the views in question.