Callback in Rails after view render (for logging purposes) - ruby-on-rails

Short version: Is there a callback when the rails view is finished rendering?
Longer explanation of my actual problem:
I have this issue where I want to generate a history-object because of some APIs I'm using. So I will be appending to this history object possibly several times before saving it. I know that I can safely save it when the view is rendered, because then there will not be any more calls to the APIs.
After quite a while of googling I can still not find any way of doing this. Is my intended approach the right one, to get a callback from the renderer that says "now everything is rendered. Go ahead and save", or should I do it in a different way?
Does such a callback even exist, or do I need to make it myself?

I would lean towards suggesting that you shouldn't be leaving functionality until after the page has rendered - you should really have completed any API calls in the controller before you start outputting the page. However, if you really must do this you can use javascript to fire off a function (such as an ajax request to an action) after a page has finished rendering.
http://api.jquery.com/ready/ should give you a good starting point!

Related

Controller-View Interactions in Rails

I'm endeavoring to learn rails and am doing so by completing some super basic projects. The current thing I'm working on is a higher-lower game - the user guesses a number, and the server checks the guess against a randomly generated secret number, and responds if the guess is 'higher' or 'lower' than the actual number.
I've got most of the game complete, but I've realized I have no idea how to actually implement notifying the user if the guess was too high or too low. Other view changes in the game are handled by rendering a whole other page, but for this one I wish to display new text in the current page.
This question isn't really to solve my problem per se, I'm just trying to get pointed in the right general direction with controller-view interactions such as these.
Currently the only way I can think to do this is
Logic in the View
Make the data of whether the user guessed higher or lower available by using an instance variable, then use ruby in the html.erb view to determine what text to display based off this.
This seems ... dumb, and in violation of things I've learned about MVC in the past. Any other suggestions would be appreciated.
The cleanest way to do this in the "Rails" way would be to have a new path in your controller, for example show_result, and render a javascript view (show_result.js.erb). Then use a simple line of javascript to update the current DOM. Remember to set your form submission or your link to :remote => true and you're good to go.

Refresh a Sitecore rendering after logon

I feel like this should be obvious, but I'm stumped. We're running Sitecore 7.1 with MVC.
There is a Header rendering that includes conditional logic depending on the status of Sitecore.Context.IsLoggedIn. Works fine.
There is a second rendering that either allows the user to log in OR displays account information. When the [HttpGet] acton is called, the controller checks IsLoggedIn and returns one of two views. When the [HttpPost] action is called (i.e. when the user logs in), The controller calls AuthenticationManager.Login() and then returns the view with the account info. Works fine.
It's a simple solution that allows us to place one rendering on the page, and it works great, except for one thing: the header rendering still shows the not-logged-in content immediately after logging in.
Caching is turned off on the header rendering and in the presentation details. When any link is clicked or the page reloads, the header updates to show the correct info. The problem is only after the initial request/response, when the login form submits and returns an alternate view. Although we've had a complete HTTP request/response cycle, it's like Sitecore doesn't bother to check anything except the rendering that was directly affected.
I know I can solve this by returning a hard Redirect() after logging in but that seems inelegant and creates annoyances, like losing ViewBag info.
What I am really looking for is a way to tell Sitecore, "hey, refresh that other rendering!"
The fact that I can find nothing at all on-line about this 'problem' tells me I might be doing something conceptually wrong.
As I see it there are two ways of handling this problem:
FormHandler
You use #Html.FormHandler to specify a Controller and an Action to handle the authentication. The FormHandler action will execute very early (see: https://twitter.com/dmo_sc/status/480001473745399809) in the page execution, before anything is rendered, and all your Renderings will have the same view of whether users are logged in or not.
Martina did a good writeup on Sitecore MVC and forms:
https://mhwelander.net/2014/05/28/posting-forms-in-sitecore-mvc-part-1-view-renderings/
https://mhwelander.net/2014/05/30/posting-forms-in-sitecore-mvc-part-2-controller-renderings/
Post-Redirect-Get
I really want Sitecore MVC to have this feature build in, as it is useful for all form submission scenarios (bar AJAX). The idea is to handle the POST request and work out what you want to respond (and store this in tempdata). Instead of returning a ViewResult you issue a redirect to the same URL, this forces a GET to the page (at this point all the logged in state is same for all Renderings) where you fish the result out of tempdata. Also P-R-G protects against resubmitting POST requests.
cprakash documented his experience doing P-R-G:
https://cprakash.com/2015/01/12/sitecore-mvc-form-post-simplified/
Off Topic: Multiple forms on single page
This will not solve the OP problem, but worth having a look at in this context:
http://reinoudvandalen.nl/blog/ultimate-fix-for-multiple-forms-on-one-page-with-sitecore-mvc/
In MVC, your renderings are executed sequentially, top to bottom. So if your header rendering comes before the login status rendering, it's going to be done before the user is logged in.
The elegant way to do this would probably be to do your post and update both elements via JavaScript. If you want to keep the header logic separate from the login status logic, your login status script could allow other components to register their own callbacks. You could even build out a client-side message bus, if you will be doing this sort of thing frequently.
You could take a look at Jeremy's approach:
https://jermdavis.wordpress.com/2016/04/04/getting-mvc-components-to-communicate/
The key takeaway, I think, is where he switches the order of the placeholders by placing the results into variables and then render them wherever you want them.
#{
HtmlString main = Html.Sitecore().Placeholder("MAIN");
HtmlString head = Html.Sitecore().Placeholder("HEAD");
}
<head>
#head
</head>
<body>
#main
</body>

Synchronous update of form data

This is basically a simple question, but I haven't found a good answer here or with Google.
We have a Ruby on Rails app with a form that needs to update a section when the user changes the selected option in a pulldown menu. The complication is that this update will be from the database - it can't realistically store and hide all the possible data when it loads. The obvious solution is an Ajax call, but the problem is that Ajax is asynchronous, and our update is inherently synchronous. We need to ensure that the user gets the updated info before submitting or doing any other work on the form.
I know one can (but shouldn't) specify that an Ajax call be synchronous, but is there a better approach to this? I hate to do a separate post and reload every time the user selects a different option in one field, but I'm not sure what the best practice is for a situation like this.
Update: I tried switching to using an XMLHttpRequest object in JavaScript, and it may work (I'm figthing with Rails routing issues right now), but it gives me a warning that the synchronous option for this object is deprecated. Is there really no accepted way to get synchronous communication between a web page and server?

Loading page while rails app starts?

I have a rails application on a shared server that also has a decently sized database, which is still growing, behind it. The application takes a long time to start/load the homepage, about 20-30 seconds for me, although some people report waiting up to several minutes.
Is there a way to flash a notice that informs people that the database may take several minutes to load while they are waiting?
It's hard to say based on your question, since we don't know exactly what your home page is showing or how it's displaying it, but assuming you are referring to an AJAX (based on the tag) call that is retrieving something from the database to be displayed on your homepage, there are a few things you can try:
Paginate the items. Is whatever you're loading a long list of items? If so, only retrieve a few at once, and let the user decide if they want to see more.
Load the rest of the page (header, footer, navigation bar, etc), and then place a loading gif spinner in the area where the content is to be loaded. If you use a javascript library like jQuery this is pretty trivial, and there are a ton of tutorials out there for it. Here is a good site for free loading indicators: http://ajaxload.info/. What you'll want to do is make the AJAX call and use your javascript library to set the loading image. Then, in the success callback for your ajax call, hide the spinner and show the content.
Load one item at a time. Make a separate ajax call for each item you're going to load, so that the user sees them coming in. This will probably end up taking longer overall (you're hitting the database more often), but the visual may be a nice psychological hack.
Look at how your database queries are set up. Are you getting everything you need in one find? That's the best way to do it, as every time you have to make another trip to the database you're increasing the wait time.
Other than that the best thing you can do is get better hardware if possible, maybe look into a VPS like linode.com.

Showing status of current request by AJAX

I'm trying to develop an application which modifies a couple of tasks of the famous Online-TODO List RememberTheMilk (rememberthemilk.com) using the REST API.
Unfortunately the modifying takes a lot of time, so I want to give a feedback to the users.
My idea was just to display a couple of text lines (e.g. modifying task 1 of n...).
Therefore I used the periodically_call_remote on my page and called a which reads a Singleton.
In the request I store the text that should be displayed in the same singleton. But I found out, that once I set up a request, the periodically_call_remote does not update the specified div.
My question to this:
1. is this a good way to implement this behaviour?
2. if it is, how do get the periodically_call_remote to work during a submit?
Using a Singleton is most definitely a bad idea. In an advanced production setup it isn't guaranteed that subsequent requests will go to the same process or to the same machine (and subsequently will have a different Singleton). Plus, if you have many users, I don't even want to think about what'll happen to those poor Singletons.
Does any of this stuff actually need to go through your Rails app? It seems like you can call the RTM API via Javascript from the page the user is on and then update the page when the XHR request is complete.

Resources