How much logic do you put in views? - ruby-on-rails

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).

Related

Rails MVC - Should database search logic go in the model or the controller

I would like to make sure my code is properly organized/designed according to the following paradigms/patterns:
- Model View Controller
- Rails Convention over Configuration
- Skinny Controller, Fat Model
I have listed them here in the order I think is most important.
My issue
After reading several articles, in particular this one and this one too, I started to move some of the logic in my controllers, to my models.
However, I can't decide whether or not to move my searching logic (explained in depth, later) from the controller to the model, even after reading more posts/articles like these: MVC Thinking, and Model vs. Controller, Separating concerns and many more not listed here.
The scenario
View
Two pages:
1 page contains a text field and submit button which sends the user's input as an argument in params in a POST request to the second page.
The second page simply renders each neatObject in a given array, let's call it #coolList.
Controller
A method, let's call it awesomeSearch, is invoked when the second page receives a POST request. (Thanks to Rails Routing)
awesomeSearch should take the user's input, available as params[:searchString], and work with the NeatObject model to build the #coolList and make that list available for the view to render.
Model
The NeatObject model handles requests from controllers and returns neatObjects back to those controllers.
The NeatObject model defines the relationship between neatObjects and other tables in our database.
Database
These are the attributes that make up each neatObject according to our database:
id - int
description - string
address - string
date_created - timestamp
What's Missing?
How the controller works with the model to get matches for the user's input.
This is the part I am confused about. The logic itself is very simple, but I am not sure which pieces belong in the model, and which pieces belong in the controller.
Should the controller pass the search string to the model, and the model pass back the results?
Should the controller ask the model for all of the neatObjects, then only keep the ones that match?
Is the solution a little of both?
To be able to ask questions about specific bits of the logic, I'll next outline the search process with more detail.
The search logic in depth
The process involves finding neatObjects that match the search string. It would be impossible to move on without defining what we consider matches for neatObjects. To keep things very simple, we will say that:
A neatObject matches a search string if the search string is contained within its description or its address, ignoring case and leading/trailing whitespace.
This definition is not guaranteed to be permanent. There are several things that may change our definition. We may need to test against more attributes than just address and description, perhaps if the database guys add a new important attribute, or the UI guys decide users should be able to search by ID. And of course, the opposite of these scenarios would mean we need to remove an attribute from the list of attributes we are testing. There are many situations that could change our definition of a match. We could even have to add or remove logic, perhaps if it is decided that we should only test the first word in the description attribute, or perhaps if we should no longer ignore case.
Now we know what defines a match and we know that our definition may change. Now we can more concretely define the search process.
Here is an outline of the steps:
Get a reference to all neatObjects
Loop through each neatObject, putting each individual one through the match test
Test passes - add/keep neatObject in results list
Test fails - do not keep neatObject for results
Make results available to the view
I will reference these steps as I show possible implementations.
Implementation
The search functionality can easily be implemented in either the NeatObject model, or the controller serving the view.
Normally, I would just write all of the logic in the controller, but after I learned about the "Skinny controller, Fat model" design, I thought it definitely applied in this situation. This article in particular made me think to reorganize my code, after I saw the author had implemented a "search-like" function in the model. The author's function did not handle user input though, so I was wondering how it should be handled.
This is how I would have written the code before learning about "SCFM":
Search logic in controller:
#searches_controller.rb
#This is the method invoked when second page receives POST request
def search
#neatObjects = NeatObjects.all.to_a
#neatObjects.delete_if {
|neatObject| !matches?(neatObject, params[:searchString])
}
end
def matches?(neatObject, searchString)
if((neatObject.description.downcase.include? searchString.downcase) ||
(neatObject.address.downcase.include? searchString.downcase))
return true
end
return false
end
This method gets its reference to all of the neatObjects (Step 1) by calling .all() on the NeatObject model. It uses the array function delete_if to perform the match test on each neatObject, and only keeps those that pass (Step 2). Step 3 is accomplished automatically automatically since we store our results in an instance variable in the controller which serves the view.
Placing the logic in the controller is very straight-forward, but when considering the "SCFM" design pattern, it seems very illogical.
I've written another option, in which the controller sends the user's input to a function in the model, which will return the the neatObjects which match the input.
Search logic in Model
#NeatObject.rb
def self.get_matches_for(searchString)
all.to_a.delete_if { |neighborhood| !matches?(searchString, neighborhood) }
end
def self.matches?(phrase, neighborhood)
fields = [neighborhood.name, neighborhood.address]
fields.map!(&:downcase)
phrase.downcase!
fields.each do |field|
if (
(phrase.include? field) ||
(field.include? phrase)
)
return true
end
end
return false
end
This method gets the complete list of neatObjects with all() (Step 1). Just like the first method, the model method uses delete_if to remove array elements (neatObjects) that don't meet a certain criteria (passing the match test) (Step 2). In this method, the controller serving the view would call get_matches_for on the NeatObject model, and store the results in an instance variable (Step 3), like this: #neatObjects = NeatObject.get_matches_for( params[:searchString] )
I do think that the model option is cleaner, and slightly more maintanable, but I'll go more in depth in the following section.
Concerns
I can see pros and cons to both the model method and the controller method, but there are things that I'm still unsure about.
When I read over that article I've referenced several times (just like I did here), it was very logical that the model defined a function to return the recently added people.
The controller didn't have to implement the logic to determine if a person had been recently added. It makes sense that the controller shouldn't, because that is dependent on the data itself. There might be a completely different implementation of the "recency" test for messages. The recent people might include people added this week, while recent messages are only those messages sent today.
A controller should just be able to say People.find_recent or Message.find_recent and know it got the correct results.
Is it correct to say the find_recent method could also be modified to take in a time symbol, and return objects for different time periods? Ex - People.find_in_time( :before_this_month ) or Messages.find_in_time( :last_year ). Does that still follow the MVC pattern and Rails convention?
Should a controller be able to find matches for user input with NeatObject.get_matches_for( searchString )?'
I think the matching logic belongs in the model, because there are certain/specific attributes that are used in testing, and those attributes are different depending on the data. We might have different attributes for different tables, and those attributes definitely shouldn't be defined by the controller. I know the controller depends on the model, not the other way around, so the model must define those attributes, even if the rest of the logic is in the controller.
And if the model defines the attributes that are used when searching, why shouldn't it define the entire search function?
The above text explains why I think the model should handle the searching logic and expresses the majority of my questions/concerns, however I do have some opinions favoring the other option.
If the model is concerned only with the data, how can one justify passing user input to it?
If the controller doesn't handle the search logic, it still needs to send the user's input to the model. Does it clean it up before it sends it? (Removing leading/trailing whitespace and downcasing the string.) Does it just send the exact input it got from the user?
Where is the testing done to make sure the input is not malicious?
Some of my biggest questions:
Does the answer for where the logic goes change for each case?
If the search/matching process was simpler, would the code's place change? For example, if the searching was simpler:
If the only attribute being tested was the address and that was unlikely to change, would we just handle the search with the controller?
If we were making an advanced search feature, where the user decided which attributes to include in the search and also controlled some other factors, there would be a lot of user input just to define the arguments to the search function. Would that be too much logic or user input to place in the model?
In conclusion
How can I always be sure that I am putting logic in the right place (MVC)?
For my specific case, with this data and this search/match process, how should I organize the code?
What guidelines can be followed when you find a gray area, or are unsure about where logic belongs?
This is something that varies a lot between cases (each application is different) but here's what I do on my end (large sports app that searches lots of tables from many different places):
start by performing small searches with non-repeating code patterns in the controller (or rarely view)
when it turns out the code is needed in more than one or two action/view I move it to the models
I also move the code to the model when the query complexity goes above the average .find or simple .where
Like this, you don't spam your model with one-time-use methods, and at the same time don't repeat the same code over multiple controllers/actions/views
As many thinks in IT and in life, It depends of the scale and the goal.
Considerations:
1) For design: If you see you are violating DRY in your controllers many times, its probably time to move your logic to models.
2) For performance: Since controllers are loaded more than models, Logic in controller tend to performs worst.
And not less important: Unless you are doing something very trivial, and you db has a few thousands rows, do NOT use db for text search. Instead, use a search engine like Solr, ElasticSearch, Sphinx, etc.

Multiple Views Same Model

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.

How much code is acceptable in a View?

I was wondering how much code is acceptable in a view ? It is acceptable to use foreach or if such if a list of items is empty.. show some message ? or should this be done in the controller ?
in a really few works
The View should containt all the code you need for your presentation logic even ForEach (if you need them)
Some people like to create HTML helper to split down the presentation logic and inclapsulate it into an adhoc method
The control should be very skinny: it should just get the user interaction and delegate them to the right component. It may contain some validation logic (user input etc) but it really depends by your business requirements
Rushino,
To address the specific example that you cite. For a list of items, I'd be tempted to include a strongly typed helper in the view that either returned the appropriate list OR simply returned an empty MvcString. As for other logic in the view, i'd keep it to a minimum as you quickly run out of options for unit tests once the view is littered with case statements and ifs and buts. Of course, there will be occasions where the judiciuos use of a few varables may be acceptable, but few and far between.
just my 2 cents

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 ...

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