Store data between action - ruby-on-rails

What the best way to store data between two controller action?
Example:
I have a big array of posts id ["2907", "2334", "2309",.... N] i create it in first step confirm and go to second step to another controller action.
Another controller action render data (calendar, groups), i select date in calendar, choose group and create one more array of date-time data confirm and go to another action
Another action manipulate with this array and array of posts id, and render date again the data what i whant to save after confirm, data safe in DB and clear all array from session.
I store all array between action in session like session[:posts_ids] = params[:posts_ids] and flash[:date_day] ||= params[:date_day]. I think it do not work for a really big data array. May be the best way store it in redis ?

This is largely opinion-based, but I think your two best options are:
Use Redis, Memcached or some other server-side cacheing solution to store the objects in memory until you need them.
Make your app more ajax-y and do all of the selection and temporary
persistence of those arrays client-side.
Session size is limited by the underlying strategy, rather than a hard limit for sessions in general. CookieStore is the default and will allow ~4k of data, because browser cookies are limited to that size. If you use database-backed sessions, you're only limited by your database server.
You should also keep in mind that using sessions to store data between requests isn't very RESTful.

Related

Storing large objects for a user session in Rails

I'm making use of Google API client gem which returns data and is then wrapped in the an object. I want to use this data between sessions. How should I store it? I thought at first I could serialize it then put it into a table, but ran into problems with the type of object it is an gave up. Actually thereafter I thought it would be neater to take the data I need and put it into an array of hashes (eg. for youtube videos - title, id, thumbnail etc) so I extracted what I needed and done so. Now, I have an array - should I store it in the database for the user or should I put it into a session var? Session var seems easier, no need to create an additional table etc but does that mean it will be stored as a cookie? Might be a rather large cookie then. Anyway advise here would be much appreciated.
First, with database storage: with ActiveRecord you can simply store JSON. So, if your object can be serialized correctly, than there are no problems to store it in DB. just add this line to your model:
serialize :data, JSON.
Though, I think you can perfectly use session var for that purpose. By default, yes, it will be stored as a cookie - but if you think it's too much information, you can configure rails to use server-side storage instead.

how to manage lifetime of variable for multiple request

I have a variable in create method in controller ,is there any way to reuse that variable with the same value in update method. How can i pass this, or how can i maintain the lifetime for the multiple requests?
Example variable:
#m = Issue.where( :project_id => #project.id ).where( :issue => "xyz" )
As I understand it, your requirement is to re-use data that was accessed during one call to your API (for creation of an API entity), during a separate call (an update). The data is fetched from the database in the first case.
Just fetch the data again, using the same query.
The database is the only data source easily accessible in both events, that will reliably hold an up-to-date value.
As this is for a RESTful API, there should be no other state information - everything should be in either the current request or the database.
If you want, you can cache data for performance, but Ruby variables are not a reliable or efficient way to do that (because there will be several Ruby processes running independently on the web server, and you don't get to manage them from the controller code) - instead you might want to consider something like memcached if the query is slow and its results are needed in many API events. However, you should normally avoid caching data except where you have a real performance issue - because you will probably need to handle cache invalidation, too.

Store a session information - one more Core Data table or separate session-file in "key-value" format (YAML, JSON)?

I have a Session class which I want to hold and store app's current session information (like lastLocation, remoteSessionToken, ...)
I have default Core Data setup with a bunch of tables and the most obvious solution I see is to create one more table "session" with two string fields: 'field' and 'value' and store session information to this table in way like I store any information to other tables
'field' 'value'
lastLocation 46.68,34.18
removeSessionToken au987asdv7tta487tv9b
...
Also, I know I could have this done using a special separate file for settings fx in YAML or JSON format but this would lead to a logical inconsistency with having both Core Data database and a file.
Is there any recommended approach for holding and persisting session information?
Unless something like the following applies, put it in user defaults or in a special purpose file in the documents directory:
You have many sessions and need to search or filter them based on some kind of predicate
You have more than one session and sessions have some kind of relationship to specific objects in the data store.
It's not a "logical inconsistency" to use Core Data and separate files. Do what makes sense. It's not likely to make sense to keep this information in your data store, so don't do it unless you have some compelling reason.
If the information could be considered sensitive, put it in the keychain.
Also, it's extremely ugly to create a generic container entity in Core Data. Using field and value fields like you describe is not a good design decision.
As long as it's not sensitive information, I would be consistent and use Core Data. A more obscure place would be to put it in NSUserDefaults.

Storing data in HttpContext.Current.Items vs ViewData

When is it appropriate to store data in HttpContext.Current.Items[...] vs storing data in ViewData[...]?
I'm trying to figure out the best practices for storing data in this collection and I'm not sure if it's safe to store user-specific data in HttpContext.Current.Items.
One use-case is passing down user credits from a base controller's OnActionExecuting(...) to be used in Controller calculations and for display in Views; I know I should be using ViewData for this, but I've had some inconsistent results with nested partial views.
Would it be correct to say that HttpContext.Current.Items[...] is to Controllers like ViewData[...] is to Views?
HttpContext.Current.Items only lasts for the duration of the request, but it is global to everything in that request.
Session obviously lasts for the entirety of the user's session, and persists between requests.
You should be able to figure out which one you need to use based on those criteria alone. Using HttpContext.Current.Items is not something I would recommend as it tends to be a kind of "global variable", and magic key strings tend to get involved, but sometimes you really do need to use it.
Additionally, although your comparison between .Items and ViewData is pretty apt, .Items differs from the way that ViewData behaves, because every View involved in the request (partial or otherwise) gets their own copy of ViewData.
The behaviour difference is clear when you do a RenderPartial and try to add something to ViewData - when you go back up to the parent view, the item is not there.

Redirect After Post in ASP.NET MVC

I am using the Redirect After Post pattern in my ASP.NET MVC application. I have
the following scenario:
User goes to /controller/index where he is asked to fill a form.
Form values are POSTed to /controller/calculate.
The Calculate action performs calculation based on input and instantiates a complex object containing the results of the operation. This object is stored in TempData and user is redirected to /controller/result.
/controller/result retrieves the result from TempData and renders them to the user.
The problem with this approach is that if the user hits F5 while viewing the results in /controller/result the page can no longer be rendered as TempData has been expired and the result object is no longer available.
This behavior is not desired by the users. One possible solution would be instead of redirecting after the POST, just rendering the results view. Now if the user hits F5 he gets a browser dialog asking if he wants to repost the form. This also was not desired.
One possible solution I thought of was to serialize the result object and passing it in the URL before redirecting but AFAIK there are some limitations in the length of a GET request and if the object gets pretty big I might hit this limitation (especially if base64 encoded).
Another possibility would be to use the Session object instead of TempData to persist the results. But before implementing this solution I would like to know if there's a better way of doing it.
UPDATE:
Further investigating the issue I found out that if I re-put the result object in TempData inside the /controller/result action it actually works:
public ActionResult Result()
{
var result = TempData["result"];
TempData["result"] = result;
return View(result);
}
But this feels kind of dirty. Could there be any side effects with this approach (such as switching to out-of-process session providers as currently I use InProc)?
Store it in the Session with some unique key and pass the key as part of the url. Then as long as the session is alive they can use the back/forward button to their heart's content and still have the URL respond properly. Alternatively, you could use the ASP cache, but I'd normally reserve that for objects that are shared among users. Of course, if you used the parameters to the calculation as the key and you found the result in the cache, you could simply re-use it.
I think redirect after post makes much more sense when the resulting Url is meaningfull.
In your case it would mean that all data required for the calculation is in the Url of /controller/result.
/controller/calculate would not do the calculation but /controller/result.
If you can get this done thinks get pretty easy: You hash the values required for the calculation and use it as the key for the cache. If the user refreshes he only hits the cache.
If you cant have a meaningfull url you could post to /controller/index. If the user hits F5 calculation would start again, but a cache with the hash as key would help again.
TempData is generally considered useful for passing messages back to the user not for storing working entities (a user refresh will nuke the contents of TempData).
I don't know of more appropriate place than the session to store this kind of information. I think the general idea is keep session as small as possible though. Personally I usually write some wrappers to add and remove specific objects to session. Cleaning them up manually where possible.
Alternatively you can store in a database in which you purge stale items on a regular basis.
I might adopt a similar idea to a lot of banks on their online banking sites by using one-time keys to verify all POSTs. You can integrate it into a html helper for forms and into your service layer (for example) for verification.
Let's say that you only want to post any instance of a form once. Add a guid to the form. If the form does not post back and the data is committed then you want to invalidate the guid and redirect to the GET action. If say the form was not valid, when the page posts back you need a new (valid) guid there in the form waiting for the next post attempt.
GUIDs are generated as required and added to a table in your DB. As they are invalidated (by POSTS, whether successful or not) they are flagged in the table. You may want to trim the table at 100 rows.. or 1000, depending on how heavy your app will be and how many rendered but not yet posted forms you may have at any one time.
I haven't really fine tuned this design but i think it might work. It wont be as smelly as the TempData and you can still adhere to the PRG pattern.
Remember, with PRG you dont want to send the new data to the GET action in a temp variable of some sort. You want to query it back from the data store, where it's now committed to.
As Michael stated, TempData has a single purpose -> store an object for one trip only and only one trip. As I understand it, TempData is essentially using the same Session object as you might use but it will automatically remove the object from the session on the next trip.
Stick with Session imho rather than push back in to TempData.

Resources