I am relatively new to MVC and very new to Ruby on Rails. I've been going through Michael Hartl's excellent Ruby on Rails Tutorial for the second time and I have a question about application architecture. In chapter three he creates some static pages with actions from the same controller. Is this common in MVC architecture?
How do you determine between which pages should have the same controller and which pages should have their own individual controller? I assume that customers and contacts would have their own controller, but what about something like a dashboard or contact page, could they maybe go to the same controller?
Actually, static pages aren't really about MVC, think about it: they are static, so they don't have business logic. Basically you'll end up with a VC instead of MVC (the model won't exist).
Usually, for static pages only, unless they need some special routing, you would go with a single controller and a bunch of actions, the direct consequence would be having a directory structure like
views/static_pages/<youstaticpage>.html.erb
That's quite nice, especially if your static pages are really static, so you end up with a maximum of ~10 pages.
The moment you need to pull data from the database, I suggest to extract that page into its own controller. So for example if you store website email/phone/address/whatever in a location and you need to fetch and use it in your About page, I suggest to create your AboutController and handle everything through it.
In this way you'll keep the StaticPagesController very clean. That being said, if you want to strictly stick with MVC, you should have one controller per static page, but would be really worthless in this case. Extract the code when you need it, it will still be very easy: the moment you don't have a simple page, extract it into its own controller.
One important thing I learned from POODR is that code must be good enough. In addition, you should start refactoring when it's needed, over-engineering it's an ugly beast. Believe me, I love over-engineering stuff.
Related
Can anybody tell me the difference between controllers and actions in ruby on rails?
I fetched this definition from the official rails guide:
A controller's purpose is to receive specific requests for the application. Routing decides
which controller receives which requests. Often, there is more than one route to each
controller, and different routes can be served by different actions. Each action's purpose is
to collect information to provide it to a view.
I am confused.
Please, make it as simple as possible since I am newbie!
Thanks!
Controllers are just Ruby Class files which have a series of instance methods inside
Basic Explanation
Rails controllers are basically files where actions (methods) are kept
Each time you access a Rails app, you're sending a request to the system. The various technologies inside Rails route that request to a certain action, where your code can use the passed data to perform some sort of action (hence the name). The actions are kept inside controllers to give the application structure
So if you access http://yourapp.com/users/new, it tells Rails to load the new method in the users controller. You can have as many actions in the controllers as you want, but you have to tell the Rails routes system they are there, otherwise they won't be accessible
Proper Explanation
Rails Controllers are just Ruby Classes, storing a series of actions
The "actions" (instance methods) work on passed data (params) to create objects that can either be passed to the model, or used inside other methods
Whenever you send a request to Rails (access a URL), it first uses the ActionDispatch middleware to send your request to the correct Class (controller) instance method (action), and then your code does something with that data
Your job as a dev is to connect the right controllers with the right models, presenting the right data the user at the right time
DISCLAIMER: I don't write code in Rails (never did). I write Sinatra modular applications and use the MVC model.
You first need to clarify the MVC model. The MVC is an approach to programming web applications (in RoR) or user interfaces in general. So MVC stands for Model-View-Controller. I will try to explain a bit, but in order to understand this, you need to practice and play with it.
The Model: If you remove the layers of abstraction, it's your database scheme. The way your application interconnects in order to retrieve information.
The View: The way these informations are retrieved elaborated and served. Essentially is what you, or the client, see in the browser.
The Controller: The controller is what interacts with the program to produce a requested view or to alter a model. You request a view when you access a chart with statistical information, and you alter the model when you input DATA on it. In Rails ecosystem, ActionController is a class with a set of predefined methods to help you perform easier and quicker standard Controller actions like update a form, etc.
So the Action Controller allows you to alter data to your models (the db), or request a route to view your data, etc.
Action is not separated from controllers, it's basically what controllers do :-). Everything else is static.
If you feel that these concepts are still hard to grasp, try building a very basic modular application in Sinatra, and you will have a ground level view of how things work.
Explanation by Analogy (simple explanation without getting too technical)
I work in a busy office. I bark out orders (i.e. 'requests') to my staff to get em to do stuff.
e.g.
Sometimes I want a document so I can read it.
“Ngozi, pass me the ABC.ASX EOFY results please?”
Yes sir!
Sometimes I ask my staff to edit an existing document:
“Sunita, can you edit that report on the state of the union address?”
“Sure!” is the response.
I organise my staff based on the type of work they do
But I have a little problem.....I have 10,000s of different types of documents. Sometimes I want to get: (I) sports results and other times I want: (ii) the evening news, while still at other times I want: (iii) a collection of Donald Trump's latest 4 am Tweets.
So I created a new system. I have a staff member directly responsible for each type of thing.
Ngozi handles ASX (Australian Stock Exchange) Financial Results. And when I want Ngozi to do something (i.e. perform some type of action) then I tell him what to do.
Sunita works mainly on politics. Sometimes I”ll ask her to something (e.g. write up a report – this is one type of 'action', or I'll ask her to bring me a certain document – another type of action - and she'll do it. I like to get Sunita to work on politics and Ngozi to work on financial results. It's best to keep their responsibilities separated.).
And Freddie works on anything pertaining to Queen.
Etc. etc.
The meaning of the analogy?
In this case, the controller would be the person – who's responsible for handling certain types of requests. And the “action” would be the particular specific thing that I want done:
e.g.
getting a document or
edit something or even
creating a new document.
Hope that clears things up.
Using Rails, I am building several sites which are very similar. I want to implement these as one Rails app answering to multiple domains, and change what is presented and the processing logic based on the domain name. The areas I need to change/skin per site are:
Views: The fields on a page differ slightly by site. Some sites have more/different fields than others, but there are some that are common across all
Models (which seems best to do this by defining a super class for the main model which varies and implement a subcalss for each site)
Controller logic. There is a lot of similarity but a few small processing differences, including which Model subclass to deal with
CSS (which seems fairly straight forward)
I have already implemented a mechanism which makes the current domain/app name visible to the views, controllers and models.
I was thinking of defining a view partial per site and using ERB logic to include the right one. The controllers seem like the least obvious part.
Any suggestions very much appreciated.
Cheers
Paul
I have implemented something similar for our application, HiringThing (http://www.hiringthing.com)
To do so, we use a before_filter on the application controller that parses request.host and determines what website the request is for. That then sets a variable #site that we reference in views, controllers and models to determine versioning requirements at runtime.
I'm just learning the basics of ASP.NET MVC and am wondering what the benefit is in breaking up website logic amongst multiple controllers versus just having a single Controller class that runs the whole website, besides simply organizing code better. (In my opinion, just the latter benefit should not be enough to affect the end user via the url due to separation of concerns: the implementation details of the site should not be being reflected in the urls the site uses, no?)
Some examples on Controllers I've been reading show different controllers for things like "Product" or "User" or "Post". These clearly correspond to classes of objects followed by actions that can be taken on those (looking at the url right now I see stackoverflow.com/questions/ask).
Is there an advantage of splitting up the website into separate controller classes like QuestionsController versus just having a single default controller and handling these actions within it, for example stackoverflow.com/ask-question (besides it looking slightly uglier).
I ask because I'm not particularly interested in making my website RESTful (I looked into it a bit but deemed it too limiting) and instead favour query string parameters to pass information about a request. Therefore, the concept of splitting a url up into controller and action doesn't make sense to me, since the action and class information will be represented in the query string.
Finally, I much prefer the simpler look of urls like www.mysite.com/about versus www.mysite.com/home/about (what does that even mean?), again leading me to wonder what the point of multiple controllers really is.
You can achieve practically any url scheme you desire with ASP.Net MVC Routing. What controllers you have and where your actions live has nothing to do with your urls. Only routing defines your url's. Therefore, there is no reason whatsoever to sacrifice code clarity and organization for the sake of a particular url scheme.
Furthermore, in most ASP.Net MVC applications I've seen, the controllers are already unwieldy, and combining them all into a single controller would increase the disorganization exponentially.
Even small sites have a handful or two of controllers. Significant sites have dozens, very large sites could have hundreds. Do you really think it is in any way at all feasible to combine dozens of controllers into a single one?
The beauty of ASP.NET MVC comes from the fact that it makes separation of concerns so simple. Unlike ASP.NET Webforms where each page is essentially the View and the Controller, in ASP.NET MVC you can abstract your model logic into separate concerns or 'feature groups'. It makes sense to have a ProductsController that handles everything to do with Products because then you can isolate each set of related functionality in your application into uniform groups that are independently testable and maintainable.
Having a DoEverythingController fundamentally defeats the reasoning behind MVC because it clumps all of the model logic together into one giant spaghetti bowl of code, as opposed to keeping it neat and organized. Furthermore, having a Controller that does everything is not especially object-oriented and resembles a more procedural approach to development like many (older) PHP websites which have some central "functions.php" or similar that does everything. It's messy and disorganized.
In regards to your final point, the routing engine in MVC allows you to construct your routes to given controller actions however you want. The About() action of ControllerX and the Contact() action of ControllerY can both have root URLs like /about and /contact so long as you define the routes accordingly.
Edit (too long for comment)
Generally speaking, the controller classes will be pretty thin as far as code and logic is concerned. Well designed controllers will often hand off more complex operations like retrieving data from the data store to some kind of service so that the surface area for failure remains small. Despite the 'thinness' of most controllers, the larger your site is, the more operations will need to occur and the bulkier your universal controller is going to become. Even in non-MVC scenarios, huge code files suck to maintain and update (like "functions.php" above, for example).
If the site you're developing with MVC is small and limited to only a few more-or-less static pages, then using a single controller for all of them might be a reasonable approach, but if you are constructing a scalable application that will change over time it would be truly defeatist to forgo the use of multiple controllers.
Is like to have all files in the same directory or keep files separated in different folders.
Keeping the application organized in separate controller help in many cases:
1) memory performances
Different from Java Servlet where the controller is shared betwen many request, in asp net mvc the controller is created for each request.
Each time the user make a request, the application need to create the controller.
Think at performances comparison betwen create in memory an instance of a fatcontroller of 100k VS one instance of a light controller of 1k.
2) OO benefit
Controllers are classes. Each time you create a new controller you extend the base controller.
In a complex application you can create yours own controrres (can be more than one) and extend the more appropriated.
For example you can create a controller for "products" and extend from it to create a controller for "vegetables products" and so on..
3) Security.
Suppose that in your application you have a page that execute the CRUD actions on a given item of your db:
- display
- edit
- update
- delete
You want to make this page reserved for registered user only.
If you put all this method in one separate controller you can put the annotation [Authorize] on the controller and by default all the methods inside the controller will be protected.
If you put all the application in one fat controller you have to be careful to place the [Authorize] on each method (what happe if you forgive to put the annotation on the delete method?)
[Authorize]
public class ProductController
public ActionResult Index(String id) {
...
}
public ActionResult Update(String id) {
...
}
public ActionResult Delete(String id) {
...
}
4) Security again.
Suppose you write a classic CRUD (Create Read Update Delete).
Now you want to delete the whole CRUD.
If you keep code separate in different controller you simply delete the controller that belog the CRUD.
If you keep all together in a fatcontroller you have to search for the methods that belog to the CRUD in the whole code.
Again: what hapen if you forget to delete the Delete method?
5) practicality
If you put all together you will have methods like this:
product_edit
product_delete
product_rate
product_create
category_edit
category_delete
category_create
If you organize code in separate controller you will have
product
edit
delte
create
rate
category
edit
delete
create
This is good for many reason: want to modify product in item? simply refactor and rename the productController in itemController.
chaiguy
i think this topic has the potential to illustrate (from the answers) the true benefits of using the controllers to do their own 'lightweight' tasks. one of the many benefits that immediately spring to mind is the fact that each controller can have pretty much the 'same' named actions irrespective of the task at hand (create, edit, delete, list etc).
couple this with a good repository pattern for the data access and some nifty T4 templates and you more or less get an easily understood 'plumbing' job created for free.
this is what makes mvc a pure joy for me - the discreet segmentation of related operations into a unified structure. as previously mentioned, what could become unweildy and cumbersome is instead rendered (no pun intended!!) familiar and focussed.
I guess if you like spaghetti, you would only have one controller.
Complexity, complexity, complexity, that is the question. Software is all about breaking a problem down into manageable units.
Hence multiple controllers.
I really like the way ASP.NET MVC works. I'd love to implement it on all new web projects moving forward, but I hit a snag in a prototype the other day that I really haven't found a good solution for, so I ask you, how would you design an MVC app that doesn't fit the typical REST pattern? As an example, the prototype I was designing would have several pages, but the pages themselves aren't necessarily bound to a domain model. For example, take a simple registration site, which might have the following pages:
/Default.aspx
/Register.aspx
/ThankYou.aspx
Occasionally, such a program might require an admin section to deal with such details as moderating sign ups or reviewing data. In a standard ASP.NET web app, I might add the following
/Admin/Default.aspx
/Admin/ListRegistrations.aspx
/Admin/ViewReports.aspx ...
Would it be an unacceptable deviation from the MVC pattern, in this case, to have two controllers such as:
Home->Index
Home->Register
Home->ThankYou
Admin->Index
Admin->ListRegistrations
Admin->Reports
My frustration with this is compounded by the fact that there is no real solid implementation of subcontrollers and areas yet. I'm aware of the "Areas" prototype put together by Phil Haack, but it's not very mature, and quite frankly, I'm not sure I like the way it's setup, but I don't really know how I'd like to see that work either.
I guess when I think MVC, I tend to think REST as well, and having controller actions that represent pages rather than actual entities or actions doesn't sit right with me. What do you think?
You can always mix ASP.NET Web Forms with MVC.
Just add
routes.IgnoreRoute("Pages/{*path}");
to your routing table and add traditional Web form pages to Pages folder of the application.
One mistake that newcomers to MVC make is to group actions into a controller for display reasons. In your case, instead of grouping the Register and ThankYou actions in with the homepage try separating them out into an AccountController as the MVC team has done in the sample project. You can use routing to set the Url's up however you want for the end-user.
As for your other actions, how about a ReportController? You could then additionally have an AdministrationController whose Index action/view contains links to various admin actions, including those on the ReportController.
Short Version: Group actions into a controller by function, not site navigation.
I usually ditch the "Home" controller as the first thing in a project and replace it with a "Page" controller. I use that one for anything that is "just" a page. Things like "FAQ", "Contact Us", etc. I do this at least partially because the default approach to the Home controller requires a new method being added every time you need even a basic, static page.
In that controller, I only have the one action: Display. That action gives all of those pages the same context object. I actually store the content for those pages in the database with a lookup "slug" and tie it into NVelocity templating, but even just static HTML or NVelocity templates in files would work too.
Anything else, like the others said, gets split into controllers by the "thing" being managed. So, a ReportController, User or AccountController, CartController, etc. Then the actions make much more sense.
When you're talking about listing the registered users, it's actually a list of users, so I'd have a UserController and do /User/Display/Registered/MostRecent or something similar. For the registration itself, /User/Register which would post to /User/SaveRegistration which could, in turn, redirect to /User/DisplayProfile/NewUserID or /Page/Display/Home from there.
You can have as many controllers as makes sense; that layout looks reasonable. Note that routes don't have to map directly to {controller}/{action}, but it keeps things simple. Looks fine to me - except I'd probably have ThankYou as a view - i.e. the Register [GET] perhaps uses a different view to Register [POST]
What is the purpose of the code behind view file in ASP.NET MVC besides setting of the generic parameter of ViewPage ?
Here's my list of reasons why code-behind can be useful taken from my own post. I'm sure there are many more.
Databinding legacy ASP.NET controls - if an alternative is not available or a temporary solution is needed.
View logic that requires recursion to create some kind of nested or hierarchical HTML.
View logic that uses temporary variables. I refuse to define local variables in my tag soup! I'd want them as properties on the view class at the very least.
Logic that is specific only to one view or model and does not belong to an HtmlHelper. As a side note I don't think an HtmlHelper should know about any 'Model' classes. Its fine if it knows about the classes defined inside a model (such as IEnumerable, but I dont think for instance you should ever have an HtmlHelper that takes a ProductModel.
HtmlHelper methods end up becoming visible from ALL your views when you type Html+dot and i really want to minimize this list as much as possible.
What if I want to write code that uses HtmlGenericControl and other classes in that namespace to generate my HTML in an object oriented way (or I have existing code that does that that I want to port).
What if I'm planning on using a different view engine in future. I might want to keep some of the logic aside from the tag soup to make it easier to reuse later.
What if I want to be able to rename my Model classes and have it automatically refactor my view without having to go to the view.aspx and change the class name.
What if I'm coordinating with an HTML designer who I don't trust to not mess up the 'tag soup' and want to write anythin beyond very basic looping in the .aspx.cs file.
If you want to sort the data based upon the view's default sort option. I really dont think the controller should be sorting data for you if you have multiple sorting options accessible only from the view.
You actually want to debug the view logic in code that actuallky looks like .cs and not HTML.
You want to write code that may be factored out later and reused elsewhere - you're just not sure yet.
You want to prototype what may become a new HtmlHelper but you haven't yet decided whether its generic enough or not to warrant creating an HtmlHelper. (basically same as previous point)
You want to create a helper method to render a partial view, but need to create a model for it by plucking data out of the main page's view and creating a model for the partial control which is based on the current loop iteration.
You believe that programming complex logic IN A SINGLE FUNCTION is an out of date and unmaintainable practice.
You did it before RC1 and didn't run into any problems !!
Yes! Some views should not need codebehind at all.
Yes! It sucks to get a stupid .designer file created in addition to .cs file.
Yes! Its kind of annoying to get those little + signs next to each view.
BUT - It's really not that hard to NOT put data access logic in the code-behind.
They are most certainly NOT evil.
Ultimately, the question you ask yourself is this:
Does this code A) Process, store, retrieve, perform operations on or analyze the data, or B) Help to display the data?
If the answer is A, it belongs in your controller. If the answer is B, then it belongs in the view.
If B, it ultimately becomes a question of style. If you have some rather long conditional operations for trying to figure out if you display something to the user, then you might hide those conditional operations in the code behind in a Property. Otherwise, it seems like most people drop the code in-line to the front end using the <% %> and <%= %> tags.
Originally, I put all my display logic inside the <% %> tags. But recently I've taken to putting anything messy (such as a lengthy conditional) in my code behind to keep my XHML clean. The trick here is discipline - it's all too tempting to start writing business logic in the code behind, which is exactly what you should not be doing in MVC.
If you're trying to move from traditional ASP.NET to ASP.NET MVC, you might aviod the code behinds until you have a feel for the practices (though it still doesn't stop you from putting business logic inside the <% %>.
There isn't a purpose. Just don't use it except for setting the model
ViewPage<Model>
See this blogpost for more info.
At this Blogpost is a working example of removing the code behind.
The only problem I'm stuck with is that it is not able to set namespaces on the class.
The codebehind provides some of the strong typing as well as the intellisense support that you get in the view. If you don't care about any of these two features, you can remove it.
For example, I typically use the NVelocity ViewEngine because it's clean and pretty straight forward.
This is a great question. Doesn't MVC exist in the ASP.NET environment, without using the specific MVC pattern.
View = aspx
Controller = aspx.cs (codebehind)
Model = POCO (Plain Old C#/VB/.NET objects)
I'm wondering why the added functionality of MVC framework is helpful. I worked significantly with Java nd MVC and Java Struts several years ago (2001), and found the concepts in MVC to be a solution for the Internet Application organization and development problems at that time, but then found that the codebehind simplified the controller concept and was quicker to develop and communicate to others. I am sure others disagree with me, and I am open to other ideas. The biggest value I see to MVC is the front controller pattern for Internet development, single entry source for Internet Application. But, on the other hand, that pattern is fairly simple to implement with current ASP.NET technologies. I have heard others say that Unit Testing is the reasoning. I can understand that also, we used JUnit with our MVC framework in 2001; but I have not been convinced that it simplifies testing to use te MVC framework.
Thanks for reading!