Multiple Views Same Model - ruby-on-rails

I have a Course Model which goes the controller and views in a restful way.
For my Course show, it is fully featured. I now want another Course show which will have a simplify page and it like to the original course show.
How can I implement this? I want it to be restful, so in my controller there should only be show, update, index, etc.
Should I create another controller that have an different name from the Model? E.g. Course2?

If it is an admin view vs. public view, I would have entirely different namespaces for two different RESTful controllers. Or if you think you're going have this summary vs. full view thing a lot, create namespaces based on that distinction.
Another option is to encoded the differences in a single ERB template. Or you could actually have the show action render different templates from the same action using some conditional logic.
Without more context though, I can't really say what's the best option. I am personally against creating non-RESTful actions unless it's really going to be a one-off thing. Non-RESTful actions tend to get out of hand in my experience and controllers can get really ugly and unintuitive.

If this is truly just displaying a subset or a different arrangement of the same information, then I think this is a job for the view. At most the controller can use the same action, but select a different view to render, such as might be done if the user wanted to see html vs plain text.
The controllers job is to interpret the model and the views job is to collect and display information. I think you would be concerned about the view having logic in it if you what you describe as a "summary" were more than just a subset of the info, for example if you started to calculate the distances being traveled or how long it would take or how much it would cost based on the data that is provided, then that would be bad.
So I this is just a subset, then I would suggest either rendering partials based on some variable set by your controller, or if organization of the display needs to be substantially difference, then the controller can select a different template to render.

Related

Rendering Navigation in MVC3

What's the best way to render Navigation in MVC3? In my app the Controller has to decide what should be in the Navigation but as far as I know there's no way to pass a Model up to the _Layout file (where the Navigation html lives) to give it this information.
You can make the model available to your layout.
Define a base class, MyBaseModel, with the properties you want available to the layout.
Have your models subclass MyBaseModel, and ensure that you populate the properties
Have your layout specify #model MyBaseModel
Use the properties
See also this blog post where a similar problem ("we often find ourselves needing to include the same information in every page") is tackled.
Best is a relative and subjective term. I would usually go with an approach similar to druttka's answer but another option is to use RenderAction() to invoke a controller action
<div>#Html.RenderAction("action", "controller")</div>
I will offer some counterpoints to #druttka's answer. But mostly, you have to decide which trade off you want to make.
If you use a model for your view, you are now forcing 2 things:
Every view must be strongly typed
Every action must call the function to populate all levels of nav included in your view model
The first point isn't so bad, because there are very few pages in a typical non-static site which wouldn't derive from a model anyway, and its easy enough to create an empty model for those pages. The second point is much more annoying however. Each function has to instantiate it's own model, and then populate the nav properties for every level of nav provided by the model. This can be quite cumbersome, but can be fairly elegantly handled in OnActionExecuted for at least nav which is not specific to a given action.
The alternative is to add the nav to the ViewBag. This can be done whenever and does not force you to specify a model for every view, which is great for the flexibility in those cases where you do not need to specify a model. It should be noted however that the ViewBag in asp.net mvc 3 is of type dynamic, which you cannot use as a parameter in a lambda function, thus preventing you from doing something like #Html.DisplayFor(viewBag => viewBag.MainNav) in your layout, which is a real drag. You can still render partial and specify the appropriate DisplayTemplate however.

How to structure views/controllers/actions(/areas?) in asp.net mvc app in this context?

At top there is some most useful info about foo.
Between horizontal lines there is some immediate actions, if they are available, to perform on/with foo.
And below is thing that bothers me. There goes tabbed, detailed information about foo.
Those tabs can hold some actions too and can be quite sovereign.
So the question is - how to properly structure this thing (what should be controllers, actions, how do they talk to each other) in order to avoid unnecessary hussle?
I'm confused cause those tabs below are like a separate island.
In model - there's that strange thing: 1 on 1 relation. It's like there's a Contest (Foo), and Participant. Tabs are detailed description of Participant.
Currently I've modeled them both as aggregate roots. But it might be a wrong choice.
So - if there are two roots, it seems natural if both of them got controllers and Contest isn't really responsible to hold all data.
It seems that sub actions would be the way to go, but I foresee some complexity. When tabs will hold some actions, they will need to know how to redirect back to Contest details and how to pass info how to render correct tab. This coupling I would like to avoid but it seems there's no way to do that.
I can think of a couple options for those tabs ... which one makes sense probably depends on what your Model looks like, how you retrieve data and, to some degree, what the rest of your app looks like.
Option 1. Partial Views with RenderPartial(). Each tab is a partial view that renders some portion of your Model. For example, you would have a FinancialInformation.aspx partial view that renders Model.FinancialInformation.
Option 2a. Sub Actions with RenderAction(). Similar to above except that each tab is responsible for pulling its own data by calling an action method either on the same controller or more likely another controller that specializes in that information.
Option 2b. Same as 2a except that the tabs are rendered on demand using AJAX.
I should point out that none of these options is mutually exclusive. You might use option 1 (RenderPartial()) for the first two tabs since that data is inherently part of your model. And you might use option 2 (RenderAction()) for the other two tabs because, for example, you might have a ChartController the specializes in rendering charts ...

best way to implement different views of a same webpage depending on certain attributes in grails

I would like to have different views of a webpage depending on certain attributes of an item that I am showing.
This is: if the item is in the category X then I show some sections of the page. In other category I show others.
There is others attributes of the item.
I am aware of the multitenant plugin, but I think that is not what I am looking for.
I am thinking of something that maps a hierarchy of attributes with a particular grails view or layout. Maybe obtaining the name of the layout and view concatening the attributes some how to respect convention over configuration.
But I am concern in maintainability.
Can you give me any pointer?
You have a bunch of options
put the branching logic in a controller, and render different views based on the data
put the branching logic in a gsp, and simply don't render different parts based on the model passed into the gsp
You can make the code clean in either way by making use of templates, to stay DRY.

How much logic do you put in views?

I am currently unconfident, if I can put a "if/else"-construct into my view?
How much logic do you put in your views?
My dilemma:
I am rendering a navigation. So, I have to differ between the current/active menu item and the rest. The current menu item gets a special css class. I don't know how to handle this in a better way than using if-else.
If you are doing MVC (hopefully you do), than the question is "Do I put the logic in the view or the controller?". I use a simple rule to find out the answer of that:
What if my view was not HTML, but an XML document?
If I will need this logic in both circumstances - its place is in the controller. If not - it's in the view.
In good MVC design you should be able to swap the views without touching the controller.
As much as is necessary to display the information. Just remember that the view is just a window into the internal state of the program. If you stripped the view layer completely away, the program should still be able to operate as usual, just without being able to see what it's doing.
edit: re your navigation, that seems like an okay use of an if statement. The information about which is active is still coming from the model, you're simply using the if statement to decide how to display it. You might consider a little bit about how you're rendering your navigation: is the information about which navigation items available, and which to render living in your view or your model?
One way you might choose to approach the situation is to have the model give you a list of navigation items, along with which one is active, and program the view to know how to generate appropriate HTML from that. That code might contain precisely one if statement total. (instead of one for each nav item).
I wouldn't worry about putting an if statement in a view. In fact, I think there's a bit too much hand-wringing (in general) about responsibilities in these kinds of situations.
If you make your views too dumb then your model can become too view-sentric (tightly coupled).
IMHO a view can do what it likes but the guiding principle should be: where does it get its information from? If the answer is "the model" then use as much logic as you like.
An "if/else" construct is fine if the view is alternating modes, e.g. formatting a U.S. address vs. a foreign address in an order screen.
However, any logic that you place into a view should not alter the model.
Add this helper to your application_helpers.rb It will surround your links with <li> and <li class="active"> if the link is the current page.
Use it in place of a link_to.
link_to 'home', root_url, optional_condition_argument_goes_here
def active_link_to(text, url, condition = nil)
if condition.nil? and String === url
condition = url == request.path
end
content_tag :li, link_to(text, url), :class => (condition && 'active')
end
(Courtesy of Mislav)
I might put if-else in a view. In most cases not. The real question in my mind is whether the logic could go anywhere else without being messier.
I tend to avoid putting control-flow logic in my views (ASP.NET MVC) except under circumstances where I may want a portion of the interface visible/not visible based on the presence or absence of data. In this case, it is view logic -- I'm determining the layout of the page, the elements of the page that are available, etc. I think that this is perfectly acceptable and preferable to having the controller determine this or multiplying views to account for minor variants. The controller needs to give the view enough information for it to be able to render the view and its variants as needed.
What I wouldn't put into the view is business logic that determines how to calculate something or whether to perform some action (except, perhaps, for role-based decisions -- these seem to crop up just about everywhere). Other than client-side validation, my business logic resides in the controller/model.
An example of where I might use if/then logic in a view is a view which displays events. In my app, events can have subevents, but subevents can't have further subevents: a two level hierarchy. On my display page, I have tabs for Details, Groups, Participants, and Subevents. These are the same for both events and subevents, with the exception of the Subevent tab. It shouldn't exist for a subevent. Rather than repeat myself by having two different views that are virtually identical except for that one tab, I've added a tiny amount of logic to the view to not render the Subevent tab if an event has none.
By the same token, I wouldn't go so far as to have a single "view" that uses logic to determine whether to show an overview or details or editing pane, etc. based on the value of some view data item. This seems an abuse of the single responsibility principle as applied to views. Each view should have a single-purpose, IMO.
Logic that is in the view should not be required to fully describe the current state of the model.
Said another way, logic in the view is acceptable if that logic is used to format or alter the visualization of the information. Logic in the view might also have a use in vetting data that is entered before taking the expense of transmitting that data to the controller (in a client/server or web application).
For instance, the view might include logic to split a list of items into multiple columns when the list is longer than N items. That split could be done in several different ways according to the exact nature of the view (e.g. http, mobile device, pdf, voice reader, Morris Code, etc, etc, ad nasium). The full view information might need to be paginated - and that can only be done in the view. Formatting logic should not ever be included in the controller or the model.
As a corner case, the view might include logic to check that a password entered for a new user meets the current security requirements (e.g. double entry of password matches; at least N characters long; does not include spaces or the "*" character; includes at least three of the following: lower case letters, upper case letters, numbers, symbols; is different than the last N passwords, no based on a dictionary word, etc, etc). Depending on the nature of the logic, vetting a password could be thought of as "formatting" or as "business logic". It might be that the check happens in two passes - one set of checks for formatting in the view, and another set of checks in the controller with info from the model (the last N passwords).

Rails Model, View, Controller, and Helper: what goes where?

In Ruby on Rails Development (or MVC in general), what quick rule should I follow as to where to put logic.
Please answer in the affirmative - With Do put this here, rather than Don't put that there.
MVC
Controller: Put code here that has to do with working out what a user wants, and deciding what to give them, working out whether they are logged in, whether they should see certain data, etc. In the end, the controller looks at requests and works out what data (Models) to show and what Views to render. If you are in doubt about whether code should go in the controller, then it probably shouldn't. Keep your controllers skinny.
View: The view should only contain the minimum code to display your data (Model), it shouldn't do lots of processing or calculating, it should be displaying data calculated (or summarized) by the Model, or generated from the Controller. If your View really needs to do processing that can't be done by the Model or Controller, put the code in a Helper. Lots of Ruby code in a View makes the pages markup hard to read.
Model: Your model should be where all your code that relates to your data (the entities that make up your site e.g. Users, Post, Accounts, Friends etc.) lives. If code needs to save, update or summarise data related to your entities, put it here. It will be re-usable across your Views and Controllers.
To add to pauliephonic's answer:
Helper: functions to make creating the view easier. For example, if you're always iterating over a list of widgets to display their price, put it into a helper (along with a partial for the actual display). Or if you have a piece of RJS that you don't want cluttering up the view, put it into a helper.
The MVC pattern is really only concerned with UI and nothing else. You shouldn't put any complex business logic in the controller as it controls the view but not the logic. The Controller should concern itself with selecting the proper view and delegate more complex stuff to the domain model (Model) or the business layer.
Domain Driven Design has a concept of Services which is a place you stick logic which needs to orchestrate a number of various types of objects which generally means logic which doesn't naturally belong on a Model class.
I generally think of the Service layer as the API of my applications. My Services layers usually map pretty closely to the requirements of the application I'm creating thus the Service layer acts as a simplification of the more complex interactions found in the lower levels of my app, i.e. you could accomplish the same goal bypassing the Service layers but you'd have to pull a lot more levers to make it work.
Note that I'm not talking about Rails here I'm talking about a general architectural style which addresses your particular problem.
Perfect explanations here already, one very simple sentence as conclusion and easy to remember:
We need SMART Models, THIN Controllers, and DUMB Views.
http://c2.com/cgi/wiki?ModelViewController
The Rails way is to have skinny controllers and fat models.
Do put stuff related to authorization/access control in the controller.
Models are all about your data. Validation, Relationships, CRUD, Business Logic
Views are about showing your data. Display and getting input only.
Controllers are about controlling what data goes from your model to your view (and which view) and from your view to your model. Controllers can also exist without models.
I like to think of the controller as a security guard/receptionist who directs you the customer(request) to the appropriate counter where you ask a teller (view) a question. The teller (view) then goes and gets the answer from a manager (model), who you never see. You the request then go back to the security guard/receptionist (controller) and wait until you are directed to go another teller (view) who tells you the answer the manager (model) told them in response to the other teller's (view) question.
Likewise if you want to tell the teller (view) something then largely the same thing happens except the second teller will tell you whether the manager accepted your information. It is also possible that the security guard/receptionist (controller) may have told you to take a hike since you were not authorized to tell the manager that information.
So to extend the metaphor, in my stereotyped and unrealistic world, tellers (views) are pretty but empty-headed and often believe anything you tell them, security guard/receptionists are minimally polite but are not very knowledgeable but they know where people should and shouldn't go and managers are really ugly and mean but know everything and can tell what is true and what isn't.
One thing that helps separate properly is avoiding the "pass local variables from controller to view" anti-pattern. Instead of this:
# app/controllers/foos_controller.rb:
class FoosController < ApplicationController
def show
#foo = Foo.find(...)
end
end
#app/views/foos/show.html.erb:
...
<%= #foo.bar %>
...
Try moving it to a getter that is available as a helper method:
# app/controllers/foos_controller.rb:
class FoosController < ApplicationController
helper_method :foo
def show
end
protected
def foo
#foo ||= Foo.find(...)
end
end
#app/views/foos/show.html.erb:
...
<%= foo.bar %>
...
This makes it easier to modify what gets put in "#foo" and how it is used. It increases separation between controller and view without making them any more complicated.
Well, it sort of depends upon what the logic has to deal with...
Often, it makes sense to push more things into your models, leaving controllers small. This ensures that this logic can easily be used from anywhere you need to access the data that your model represents. Views should contain almost no logic. So really, in general, you should strive to make it so that you Don't Repeat Yourself.
Also, a quick bit of google reveals a few more concrete examples of what goes where.
Model: validation requirements, data relationships, create methods, update methods, destroy methods, find methods (note that you should have not only the generic versions of these methods, but if there is something you are doing a lot, like finding people with red hair by last name, then you should extract that logic so that all you have to do is call the find_redH_by_name("smith") or something like that)
View: This should be all about formatting of data, not the processing of data.
Controller: This is where data processing goes. From the internet: "The controller’s purpose is to respond to the action requested by the user, take any parameters the user has set, process the data, interact with the model, and then pass the requested data, in final form, off to the view."
Hope that helps.
In simple terms, generally,
Models will have all the codes related to table(s), their simple or complex relationships (think them as sql queries involving multiple tables), manipulation of the data/variables to arrive at a result using the business logic.
Controllers will have code/pointers towards the relevant models for the job requested.
Views will accept the user input/interaction and display the resultant response.
Any major deviation from these will put unwanted strain on that part and the overall application performance may get impacted.
Testing, Testing ...
Put as much logic as possible in the model and then you will be able to test it properly. Unit tests test the data and the way it is formed by testing the model, and functional tests test the way it is routed or controlled by testing the controllers, so it follows that you can't test the integrity of the data unless it is in the model.
j

Resources