Should I use Response.Write directly from a View? - asp.net-mvc

I have been trying to avoid using Response.Write(...) directly in my MVC Views. The reason being that I just need to type the string literals and the view engine knows what to do. However, in certain circumstances I seem to be creating way too many pointy brackets (<% %>). So, which of these 2 code snippets do you find more acceptable?
<% if (true)
{
Response.Write(Model.SomeValue);
} %>
Or
<% if (true) { %>
<%= Model.SomeValue %>
<% } %>

This is why Html Helpers exist (to avoid spaghetti code as much as possible):
<%= Html.MySuperHelper(Model.SomeValue) %>
Every time you need write an if statement in a view you might ask yourself the question: wouldn't it be better to write a helper method (which as a bonus could be unit tested) instead?

How about a third possibility?
<%= condition ? Html.Encode(Model.SomeValue) : "" %>
Although in practice you should keep all but the very simplest logic out of your view altogether. Either do the work in your controller or wrap the logic up in a HTML helper of some kind.

Or a fourth:
<%= condition ? Html.Encode(Model.SomeValue) : "" %>

Related

Move logic like this to the controller or model rather than the view?

I have this logic currently in my view
<% tools_count = #job.tools.count - 1 %>
<% count = 0 %>
<% #job.tools.each do |u|%>
<%= u.name %>
<% if count != tools_count %>
<% count += 1 %>
<%= "," %>
<%end%>
<% end %>
Which just loops through some users relations and puts in a , unless it is the end of the list.
My question: This kind of logic looks really messy and clogs up my views I know there must be a better way of doing this by moving it into the controller or maybe model, does anyone know the correct way to do this kind of logic?
You can add a method like this to your Job model:
def tool_names
tools.map(&:name).join(',')
end
And use it in your view like this:
<%= #job.tool_names %>
There are couple of ways to avoid putting this kind of logic in the view layer:
Create an instance method in the model class (as spickermann suggested)
This will work for simple logic and simple projects. However, when you will want to use some helpers from ActionView::Helpers such as jobs_path or number_to_currency, a model is not a good place for it.
Create a helper method in helper modules eq. JobHelpers
Generally you can put any helper methods related to view layer in helpers. For example to share common methods for building a view components.
Use the decorator/presenter pattern and put there the view logic so model won't be polluted. Here is some more explanation about the pattern and sample implementation using draper gem: http://johnotander.com/rails/2014/03/07/decorators-on-rails/
You can do it in a single line like
<%= #job.tools.map(&:name).join(',') %>

If else statements in .html.erb in views

In rails, I often run into the situation where inside the views I'll do something like
<% if #some_condition_previusly_established_in_a_controller %>
<div class="one">123</div>
<% else %>
<div class="two">something else</div>
<% end %>
It looks a bit cluttery. Is this an acceptable way of working with views or not?
Unless you can think of a way to re-write this as a helper method, you're basically stuck with it looking kind of ugly. That's just how ERB is, as it was intended to be a minimal way of injecting Ruby into an otherwise plain-text template, not as something necessarily streamlined or elegant.
The good news is a syntax-highlighting editor will usually make your <% ... %> ERB blocks look visually different from your HTML so that can dramatically improve readability.
It's also why other representations like HAML have been created where that syntax is a lot less cluttered:
- if some_condition_previusly_established_in_a_controller
.one 123
- else
.two something else
For one or two such conditional logic in your views, I guess its fine but when your code gets bigger and you have multiple if..else..end and looks "cluttery", I think you should look at implementing "Presenter Pattern" which greatly cleans up your views by separating your logic to Presenters.
Here is a great tutorial I followed from Ryan Bates in his Rails Casts series on "Presenter Patterns from scratch". http://railscasts.com/episodes/287-presenters-from-scratch.
Have you tried?
<% #some_condition_previusly_established_in_a_controller ? <div class="one">123</div> : <div class="two">something else</div> %>
If your view contains lots of tags and HTML elements, you can put them into partials and logic into model
View:
<%= render :partial => #model.status %>
<%= render :partial => "file/path/#{#model.status}" %> # if your partial is in some different folder
If your status is one, then it would render the file _one.html.erb
If it is two, then it would render the file _two.html.erb automatically.
Model:
def status
if #some_condition
"one"
else
"two"
end
end
Yes, that is the standard (and yes, it looks cluttery).
If you're looking for a possibly cleaner alternative, check out: Conditional tag wrapping in Rails / ERB
You can always move the logic to the controller and leave the view clean(er).
Controller:
if #some_condition
#div_class = :one
#div_content = 123
else
#div_class = :two
#div_content = 'something else'
end
View:
<div class="<%= #div_class %>"><%= #div_content %></div>
Or using a helper:
<%= content_tag :div, #div_content, class: #div_class %>

Highly conditional Rails 3 views

I've got a Rails 3 application where I'm using quite a few conditional statements to change the design of the page. What is the best practice for keeping the logic out of the view for having such drastic amounts of conditionals?
Hypothetical Example:
<% unless #ethos.blank? %>
<%= unless #work.nil? do %>
<%= link_to "Add Work", work_path %>
<% end %>
<%= #ethos.tagline %>
<% end %>
I've got many more conditionals inside of other conditionals. What is the best way to manage this inside of one view?
You should avoid complex conditionals (and most conditionals) in views. Extract them to a Helper, or better yet, to some kind of "presenter" so that you can work with a receiver instead of those "global looking/feeling helpers"
SomeHelper
module SomeHelper
def work_link
(#ethos.present? && #work) ? link_to("Add Work", work_path) : nil
end
end
View
<%= work_link %>
<%= #ethos.tagline if #ethos.present? %>
If #ethos is likely to be nil as opposed to an empty [] array, you could instead use:
<%= #ethos.try :tagline %>
Also note that in your original view <%= unless #work.nil? do %> should have been using a - and not a =.
Oh, and I encourage you to use HAML over ERB. With HAML, the view looks like this (easier to read, isn't it) :
= work_link %>
= #ethos. try :tagline
Your original view would look like this in HAML (remember, avoid conditionals in views as much as possible!)
- unless #ethos.blank?
- unless #work.nil? do
= link_to "Add Work", work_path
= #ethos.tagline
If the code works, what is your concern? Is it aesthetics or are you having difficulty reasoning about what the code is doing because there is so much nesting?.
The simplest solution is probably just to move the conditionals inline.
<%= link_to("Add Work", work_path) if #ethos.present? && #work %>
<%= #ethos.tagline if #ethos.present? %>
This will improve readability (and therefore maintainability), though it may not go far enough to keep the Rails purists happy. Zabba's answer presents several great choices that go further down the rabbit hole.

Display #obj#{count} properly in rails

How would i get <%= "#obj#{count}" %> to actually display the variable value in the DOM instead of #obj0, #obj1, etc
I've got variable #obj0, #obj1, #obj2, etc that I need to display
A couple of ways.
First, the most correct (IMHO) is to put all your vars to an array and index that.
arr = [#obj0, #obj1, #obj2]
<%= arr[count] %>
Another option is to use eval. Avoid this (unless you really know what you're doing).
<%= eval("obj#{count}") %>
I am not quite sure what you are going for but I think you want
<%= #obj.count %>

"if" considered harmful in ASP.NET MVC View (.aspx) files?

I remember seeing a blog (or something) that said you should not use <% if ... %> in .aspx files in ASP.NET MVC, but I can't remember what it said the alternative is. Can anyone remember seeing this and point me to it?
Basically what it means is that you shouldn't have huge if statements in your Views, your Controllers and ViewModels should be able to handle the logic. Example:
<h2 class="title">
<% if (ViewData["category"] == null { %>
All Products
<% } else { % >
<%= ViewData["category"] %>
<% } %>
</h2>
Should be:
<h2 class="title>
<%= Model.Title %>
</h2>
If your controllers and ViewModels can't handle the logic, you should write Html Helpers for more complicated logic (thus making it reusable and more readable).
<h2 class="title>
<%= Html.GetPageTitle(Model.Category) %>
</h2>
I think what you're referring to is a post by Rob Conery, where he mentions a rule he uses:
If there's an if, make a helper
So to answer your question, the idea is that if you find yourself needing to use if in your View, you should consider adding a helper extension method to render that part of your View instead.
I'm not sure if this is what you saw, but here is a blog that mentions it. See item #11.
As i think the best approach for this is try to handle your if condition in controller and pass the specific view for required result or pass the View name in a variable to render.
public class HomeController :Controller
{
public ActionResult Category(string? category)
{
View viewToReturn;
if (category == null)
viewToReturn = View("CategoryList", repo.GetAllCategory); /// it is a View
else
viewToReturn = View("Category", repo.GetCategory(category)); /// it is a View
return viewToReturn;
}
}
Well, Martin answer is also from best practices.
I feel that is just fine. It allows for the view to have control of its presentation.
I suspect that the point was an attempt to avoid spaghetti code rather than restrict the use of "if"s, here is a link to a Rob Conery blog about this, he does actually mention using helpers instead of Ifs so this may be what you saw ASP.NET MVC: Avoiding Tag Soup
Is this the issue you're referring to?
binding expressions can not be used in statement block <% %>, just as
statements can not be used in a binding expression block <%# %>
-- bruce (sqlwork.com)
"Jason" <> wrote in message
news:23C11F83-A2AA-406D-BDEC-...
What is wrong with the following if statement in my aspx page?
"T" Then%>
I get error that says: BC30201: Expression expected.
Bruce Barker

Resources