ASP.NET TempData persists between requests - asp.net-mvc

I am using temp data as follow in my controllers - very simple, when there is a problem:
TempData("StatusMessage") = "You have no items set to Auto-Ship."
Then on every page I have a user control as follows:
<div class="error-container">
<% If TempData.ContainsKey("ErrorMessage") Then%>
<script> $('div.error-container').show();</script>
<div class="msg-error"><p><%=TempData("ErrorMessage") %></p></div>
<% End If%>
<% If TempData.ContainsKey("StatusMessage") Then%>
<script> $('div.error-container').show();</script>
<div class="msg-status"><p><%=TempData("StatusMessage")%></p></div>
<% End If%>
<ul></ul>
</div>
Problem is when I do have an error added to tempdata it shows up properly on the first request but ALSO shows up again on the next request as well - which is obviously very confusing and not a desired behavior.
I am not using any IoC, I did see the post with the same problems when using that.

The sole purpose of TempData is to persist until the next request. Stuff you do not want to persist until the next request should go into ViewData, instead.
Realistically, this means that TempData is only safe to use when redirecting. When not redirecting, the "next request" could be anything.

would this be acceptable (removing the error once it has been shown):
<% If TempData.ContainsKey("ErrorMessage") Then %>
<script> $('div.error-container').show();</script>
<div class="msg-error"><p><%=TempData("ErrorMessage") %></p></div>
<%
TempData.Remove("ErrorMessage")
End If
%>

Related

RoR Render errors partial if edit fails

the problem I have is probably easy to solve, although I did a lot of search and cant find a solution.
I have in my _errors.html.erb
<% if obj.errors.any? %>
<div class="row">
<div class="col-md-8 col-md-offset-2 col-xs-12">
<div class="panel panel-danger">
<div class="panel-heading">
<h2 class="panel-title">
<%= pluralize(obj.errors.count, "error") %>
prohibided this form from being saved:
</h2>
<div class="panel-body">
<ul>
<% obj.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
</div>
</div>
</div>
</div>
<% end %>
Then I have in my edit.html.erb that has a form and:
<%= render 'layouts/errors', obj: #my_obj_here %>
Then in the controller update/create (lets use the update as example):
def update
if #my_obj_here.update(params[:my_obj_here].permit(:body))
redirect_to my_path_here_path(#my_obj_here), notice: "Something."
else
render 'edit'
end
end
The issue happens when I try to update and the submit info is invalid, which will fall into the "render 'edit'"
The errors show correctly (in this case max length 100) but my url changes from:
my_obj_here/1/edit to my_obj_here/1
which should not happen.
So next I tried replacing the "render 'edit'" with "redirect_to :back" but this just ignores the
<%= render 'layouts/errors', obj: #my_obj_here %> in the edit.html.erb.
Can someone help me out figuring out how to render the same my_obj_here/1/edit?
I believe I need to use the "render" my method because the redirect will just skip the errors partial.
Also, in my update method you probably noticed this "if true":
redirect_to my_path_here_path(#my_obj_here), notice: "Something."
I could the the same and just change my code to:
redirect_to :back, :notice => "something."
This would work, but does not show the errors as I want them to shown when my the errors partial is used.
The errors show correctly (in this case max length 100) but my url
changes from: my_obj_here/1/edit to my_obj_here/1 which should not
happen.
This is is a very common misconception. Rails uses RESTful conventions where the HTTP methods used are extremely important.
When you click an edit link it you're performing a GET request to my_obj_here/1/edit. This is an idempotent action - the result is always the same and it does not alter any resource. In fact the new and edit actions in Rails don't do anything but display forms.
When you submit the form your sending a PATCH request to my_obj_here/1. This is a non-idempotent request as it alters the resource. When the validation fails and you render you're actually displaying the result of an attempt to update a resource. This is fundamentally different than the GET request to my_obj_here/1/edit - it's not cacheable and cannot be revisited.
http://guides.rubyonrails.org/routing.html#resource-routing-the-rails-default

Application.html.erb template inheritance

I have a situation in rails (version 4.04, ruby version 2.1) where I've been using the standard application.html.erb to define the main framework for my site, header, footer, nav bar, etc. When I got to an inner div, call it, inner-content, thats where I put a <% yield %> statement so that the sub template can take over and place its content in the correct place (for example products#show or products#index have show.html.erb and index.html.erb respectively which just the content for those actions).
The problem is I realized I was duplicated some code in those sub templates. In ever one of them (except one) I always was starting off like this:
<div class="columns large-6 medium-6 center-small">
<div class="inner_wrapper">
And I was always ending like this:
</div>
</div>
So I was thinking, I shouldn't be repeating all this code. I should move this into application.html.erb so that every template automatically gets the inner-content set up correctly.
The problem is that one action I was talking about. There is one action that has a different setup. I don't want to have to type in those extra 2 divs for every sub-layout except one. Is there a better way to do this?
One way could be to check which controller your currently using this in your application.html.erb
<% if params[:controller] == "controller name" %>
<div>
<%= yield %>
</div>
<% else %>
<div class="different div">
<%= yield %>
</div>
<% end %>
Not sure if this the best way, but its one way to do it.
Create a different layout file and call it maybe products_layout.html.erb.
Then in the controller
class ProductsController < ApplicationController
layout: 'products_layout'
....
end
Or do it on a per action
def show
render 'show', layout: 'products_layout'
end
http://guides.rubyonrails.org/layouts_and_rendering.html

Rails 4: Flash message persists for the next page view

I am using the following code in my layout to display two types of flash messages:
<% if !flash[:notice].nil? %>
<div class="row">
<div class="flash notice col-xs-12">
<%= flash[:notice] %>
</div>
</div>
<% end %>
<% if !flash[:error].nil? %>
<div class="row">
<div class="flash error col-xs-12">
<%= flash[:error] %>
</div>
</div>
<% end %>
<%= debug(flash[:notice]) %>
<%= debug(flash[:error]) %>
They both work fine, but whenever one is triggered, it will still appear for one additional page view. I'm not using any caching gems.
Why is this happening? And how do I fix it?
Use flash.now instead of flash.
The flash variable is intended to be used before a redirect, and it persists on the resulting page for one request. This means that if we do not redirect, and instead simply render a page, the flash message will persist for two requests: it appears on the rendered page but is still waiting for a redirect (i.e., a second request), and thus the message will appear again if you click a link.
To avoid this weird behavior, when rendering rather than redirecting we use flash.now instead of flash.
The flash.now object is used for displaying flash messages on a rendered page. As per my assumption, if you ever find a random flash message where you do not expect it, you can resolve it by replacing flash with flash.now.

rails pagination issue with tabs

i was wondering if it was possible to only affect one tab when clicking through pagination? im using the will_paginate gem
i have something that looks like...
<div class="tab-content">
<div class="tab-pane active span8" id="received">
<h3>Received Messages</h3>
<%= render 'received_message_feed'%>
</div>
<div class="tab-pane span8" id="sent">
<h3>Sent Messages</h3>
<%= render 'sent_message_feed'%>
</div>
</div>
which renders...
<% if #sent_message_items.any? %>
<ol class="microposts">
<%= render partial: 'shared/message_item', collection: #sent_message_items %>
</ol>
<%= will_paginate #sent_message_items %>
<% end %>
i have an equivalent received_message partial as well.
in my first block of code, i have 2 tabs, one for my received messages and one for my sent messages. lets say i click on my sent tab and then click on page 2. two problems arise from this.
the page refreshes and goes to my received messages tab, which is at first active tab. is there a way to make it go back to sent?
the bigger problem, when i click on page 2 while in sent tab, it will also load page 2 on my received tab. is there a way to prevent this?
im not sure how to fix this... help would be appreciated. thank you!
UPDATE.
i winded up using ajax pagination, so then the page doesn't ever reload and problem 1 is circumvented. however problem 2 is still an issue...
i fixed it.
i winded up using ajax pagination, so then the page doesn't ever reload and problem 1 is circumvented.
and as for problem 2, this saved the day
http://blog.devinterface.com/2011/08/tips-multiple-pagination-with-will_paginate/

WebForms view engine looks ugly, any way to beautify it?

When I look at an MVC view which I wrote, it all looks like tag spaghetti to me especially with default color scheme of VS 2008. It's all <% yellow tags %> everywhere. It's really hard to distinguish server and client side code.
In classic ASP it wasn't that bad because usually server-side code blocks weren't as interleaved as lightweight MVC views. They were big chunks thus easily distinguishable. Now there is almost a 1:1 interleave between client-side and server-side code (e.g. one line client, one line server, goes on). I'm on the verge of having an epilepsy attack when I try to understand what a view produces.
If I could at least have a separate background color for server-side code, I think it would help. VS2008 doesn't allow it though.
I removed yellow background color from <%/%> tags, it looks better now, at least fixed the twitch in my eye, but it's still hard to track a view's flow.
I'm also ok with alternative view engines to fix this problem but I don't know if there is any that provides some of WebForms' luxuries:
Syntax highlighting for server-side code
Intellisense
Compiled
I looked at view engines listed in SO, specifically Spark, but I didn't like how it mingles with HTML code. I think it makes the mentioned problem worse.
Here is a sample code that I don't like:
<%# Page Title="" Language="C#"
MasterPageFile="~/Views/Shared/site.master"
Inherits="System.Web.Mvc.ViewPage<SomeModel>" %>
<%# Import Namespace="SomeHelpers" %>
<asp:Content ID="Content1" ContentPlaceHolderID="body" runat="server">
<h1><%= Html.Encode(Model.Title) %></h1><br /><br />
<% if (Model.Found) { %>
<% foreach (var item in Model.List) { %>
<div class="item">
<%= item.ProductID %> - <%= Html.SomeHelper(item.Description, 32000) %>
<div class="itemsub">(<%= Html.SomeOtherHelper(item.Customer) %>,
<%= Tools.AnotherHelper(item.OrderDate, item.ShipDate) %>)</div>
</div>
<% } %>
<% } else { %>
Item Not Found <br />
<% if (Model.Items.Count > 0) { %>
Some Text Here<br />
<ul>
<% foreach(var i in Model.Items) { %>
<li><%= Html.SomeHelper(i) %></li>
<% } %>
</ul>
<% } %>
<% } %>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="title" runat="server">
<%= Html.Encode(Model.Title) %> - Badass Web Site
</asp:Content>
After pasting the code I noticed that SO does a better job in highlighting server/client-side code properly :) I don't think this kind of highlighting is possible in VS2008 though (you'd have to change C# highlighting completely which I wouldn't prefer).
1. Partial Views are Your Friend
Use RenderPartial and separate partial views for any item that falls within a loop. This also can help with live updating with ajax because you can get the rendered HTML for a single item very easily without doing a page refresh.
<% foreach (var item in Model.List) { %>
<div class="item">
<%= item.ProductID %> - <%= Html.SomeHelper(item.Description, 32000) %>
<div class="itemsub">(<%= Html.SomeOtherHelper(item.Customer) %>,
<%= Tools.AnotherHelper(item.OrderDate, item.ShipDate) %>)</div>
</div>
<% } %>
To:
<% foreach (var item in Model.List)
Html.RenderPartial("itemTemplate", item ); %>
2. Make the ViewModel pull its Weight
Do a lot more string manipulation and logic in your view models instead of loading up with single use Html helpers or similar. Maybe put HtmlEncoding in your ViewModels property setters? Or use methods like GetBoldedFirstName() in your ViewModel
Now this does kind of muddle the separation between C# and HTML markup BUT your Html markup will thank you for being cleaner. I personally don't like having 100s of single use Helpers floating around and think this technique makes the markup read better.
<div class="item">
<%= item.ProductID %> - <%= Html.SomeHelper(item.Description, 32000) %>
<div class="itemsub">(<%= Html.SomeOtherHelper(item.Customer) %>,
<%= Tools.AnotherHelper(item.OrderDate, item.ShipDate) %>)</div>
</div>
To:
<div class="item">
<%= item.ProductID %> - <%= item.FormattedDescription(3200) %>
<div class="itemsub">
(<%= item.GetCustomerName() %>,
<%= item.GetPrettyOrderStatusString() )
</div>
</div>
3. Use an Empty View
I try and keep my markup as stupid as possible and prefer to bake as much logic into the actual view model or action method I can.
For "empty" pages that I try to do is make a shared view for all my empty grids just like you would make a single 404 page for a website. Your controller should know that you have nothing to show and return the appropriate View.
You'll save is a lot of nesting and Count>0/empty/null checking in your markup.
Rob Connery has an excellent article on this topic as well:
http://blog.wekeroad.com/blog/asp-net-mvc-avoiding-tag-soup/
Well, Spark has everything you mentioned - syntax highlighting, Intellisense (works 80% though), views compilation and precompilation. And you're not forced to "mingle" HTML code, you can still use manual C# code, and even existing WebForms engine markup!
So either of the following will work in Spark
<% foreach (var product in Model) { %>
<li><%= product.Name %></li>
<% } %>
# foreach (var product in Model) {
<li>${product.Name}</li>
# }
<li each="var product in Model">${product.Name}</li>
To me the latter is a clear winner. But at least you have choice.

Resources