Concurrent photo and note uploading - ruby-on-rails

I have this requirement whereby the user is uploading a photo from the phone, and typing a note along with the photo
However, to vastly improve responsiveness, I would like to start uploading the photo before the user has finished typing the note (the same technique instagram uses)
So, there are 3 scenarios:
- the photo uploading finishes, then the note is submitted
- the note is submitted, then the photo finishes uploading
- the note and photo finishes uploading at the same time
I am using a unique token, as well as after_create hooks now to check and save.
a unique uuid comes along with both the photo upload and the note
store the photo in a temporary store with the uniqueid
when the photo is saved (after_create), check if there are any notes with the uniqueid. If so, attach the photo to note.
store the note with the uniqueid
when the note is saved (after_create), check if there are any photos with the uniqueid. If so, attach note to photo
This seems like a rather common problem, and I am wondering whether there are any accepted patterns / solutions around this? I am using mongoid and rails 3.2

To avoid concurrency problems, and UI confusions. What I would do, in your case, is:
User choses the photo -> set local variable in JS(client) -> servers starts uploading the photo
( when server respond back from the photo upload, unset the local js var )
User write notes
User submits the form -> you check if the js variable is set or not, if it is, means that photo was not uploaded yet, so you show a message. Otherwise you just submit the form with the note.
If you simplify your flow to be something like that, you should not have too much edgecases to have to debug and fix.
The only potential risk in here, is a 'deadlock' case, lets say for some reason server never send back a response to client, which never unset the js var. To avoid those cases you could have a big timeout on the client, that if there server dont respond within that timeout you show an error message.

Related

PHAsset Create with Adjustment Data in One Go

TL, DR:
I want to create a new asset in the photo library and apply adjustment data (edits) to it, without the user being prompted twice.
The Background
I am developing an iOS photo editing extension, and providing similar functionality in the container app.
For better code reuse and modularity, I am adopting a PHContentEditingController-based flow on both the extension (required) and the container app, bundling all the shared components in an embedded framework that both the app and the extension link against (as recommended by Apple).
Unlike the app extension, which is "passed" an image to edit by the Photos app and executes under its supervision, the container app needs to request changes to the asset library, each resulting in the user being prompted for authorization.
On launch, the app offers the user two options for sourcing the image to edit:
Opening an existing photo from the library, or
Taking a new photo using the camera.
(both options rely on UIImagePickerController, of course)
Right now, the images read from the library undergo the same editing flow as they would within the app extension, with the only difference that my own UI code manually calls finishContentEditing(completionHandler:) on the (shared) object that adopts the PHContentEditingController protocol, and, on completion, it further calls the PHAssetLibrary method performChanges(_:completionHandler) (which triggers the authorization prompt).
This means that edits made within the container app can be reverted when re-editing the same image with the extension in the Photos app (and potentially vice-versa, too, once I get around supporting adjustment data).
For new images taken with the camera, however, I am taking a different approach. After applying the filters, I just save the result to the photo library using the legacy function:
UIImageWriteToSavedPhotosAlbum(_:_:_:_:)
(back from the time when argument labels weren't a thing yet :-)
The Problem
The problem with this approach is that edits are always 'baked in' for images taken with the camera and edited within the app (the can't be reverted). This feels arbitrary and perhaps even confusing to the user, so I'm looking for a more unified approach.
I could save the photo to the library right after the user takes it, and from there use the same flow as with existing assets, but this means that I need to modiufy the library twice:
Create a new asset
Save edits to the new asset
...which will result in the user being asked for permission twice: Once before editing the image, and once again on committing the edits.
So, my question is:
Is There a Way to Create a Library Asset "In One Go", Original Image and Adjustment Data?
Although I haven't tried this on my code yet (I have more urgent issues now), I seem to have found what seems to be the exact answer to my question in Apple's documentation for one of the initializers of the PHContentEditingOutput class:
init(placeholderForCreatedAsset: PHObjectPlaceholder)
From the docs:
Discussion
Use this method if you want to add a new asset to the Photos library
with edited content, as opposed to editing the content of an asset
after adding it to the library. For example, you might use this option
if your app applies filters to photos it captures with the device
camera—instead of saving only the filtered image to the Photos
library, your app can save both the filtered and the original image,
allowing the user to revert to the original image or apply different
filters later.
Also:
Note
If your app edits the contents of assets already in the Photos
library—including assets your app has itself recently added—Photos
prompts the user for permission to change the asset’s content. If
instead your app uses the init(placeholderForCreatedAsset:) method to
create an asset with edited content, Photos recognizes your app’s
ownership of the content and therefore does not need to prompt the
user for permission to edit it.
I guess we all need a healthy dose of RTFM once in a while! :-)

What is the correct process to upload S3 object to Database

I have this confusion, on how to upload S3 object that being response from IOS to the server, Im using IOS AWS SDK. Let me give a couple of scenario
Illustration
Once I click next, it will save to S3 using IOS AWSK SDK.
Once saved it will go to this screen
This is where I get confused.
Should I submit the media object to S3 first, and get the response back and then segue it to the next screen, and include it in the POST header?
Should I saved the media object to S3 on the second screen, and do everything on the second screen?
Which method is more efficient?
There are pros and cons to both the approaches. It really depends on your use case -
First approach -
Pro - Your form posting will take less time as you would have already posted the object to S3.
Con - What if the user decides to leave the form screen without filling it? You would have a waste object on S3 and you would have to delete it separately.
Second approach -
Pro - You'll post the Object to S3 only when the user submits the form. This way you'll not be creating any unnecessary objects on S3.
Con - The user will have to wait longer as both calls are being made serially.
Now if your use case is such that very few users would cancel the form screen then it would make sense to go with the first approach else its better to go with the second approach as its more easy to maintain.

Core data posting data to web service preventing duplicate posts?

This is perhaps a simple one but I have been running around in circles for a few hours trying to work out the best way to do this.
Essentially my app allows a user to create a post entry, which is then saved into core data and then posted to a web service if the Internet is available during this time the posting to the web service is done in a background thread allowing the user to carry on working.
The records are flagged SendToWebService = 1
My issue now is that the user can view a list of the entries they made in the app and select to re post it to the web service if it has not already happened, however this is causing duplicate posts as the previous background thread is still working on posting the entry as it is uploading an image or something big.
Any suggestions on how to best handle this?
Thanks
I would suggest having 3 flags for uploads in your core data object.
0 => upload failed,
1 => currently uploading,
2 => upload complete.
As soon as the user selects to upload the post set the flag to currently uploading, in which case you set the update button to a spinner or something. When it completes, either failed or finished then change the upload button to done or re-upload depending on the flag.
This seems like the obvious answer hope I understood your question correctly.
how about this, set SendToWebService=1 for the post that you are currently sending, if it goes through leave it 1 or delete the entry (depending on your implementation) but for some reason if it fails to post, set your SendToWebService back to 0. so when a post is in progress of being sent, it would appear as if its sent.
But if you want to be more transparent about the functionality, create another Boolean called InProgress or something and then turn it 1 when you are sending a request and do not let user post posts who have InProgress True and you can show which ones are in process of being sent in the UI as well, if it gets posted, turn your SendToWebService=1 , if not then Turn your InProgress again to 0
Hope that helped
In case the user is viewing the list of entries from the database than the easiest way wold be:
When post event happen, save the post in database as sent to server and start the background thread.
When the thread completes the run, check if the upload failed mark the entry in db as not uploaded, if it was with success do nothing.
By saving the state of the upload in db, the state will persist even if the user changes the screen or closes the app.

Given a Facebook page URL, save as ID in Rails

tl;dr: In Rails, what is the recommended way of taking one form of input (in this case, a URL), and converting it to something else (in this case, a Facebook ID using their graph API) before saving it?
I'm working on creating a (very simple) site to track some Facebook and Twitter accounts. In both cases, I want a user to enter a URL into a form, but I'd like to then convert that URL into a (Facebook or Twitter) ID before saving to the database, for the sake of consistency and future-proofing.
My experience with Rails is very limited (just finished Michael Hartl's RailsTutorial), and I'm not sure how to set up my form to perform some action on the input before saving it. Any suggestions?
The common pattern for this, is doing it in the before_save callback (see http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html). However, as these operation(s) sometime take very noticeable time, it's better to do it in the background using DelayedJob, Resque, Sidekiq or at least girl_friday. The enqueuing of the job can still go into the before_save callback. And you probably want to check there if the id is already known, so it doesn't need to fetch it again.

How Can I Verify A Download Has Been Completed?

We're using ASP.NET MVC and our action does this:
pull records from DB
mark records as downloaded
push zipped download to browser
Now the problem comes when the download doesn't complete for some reason - maybe the user clicks "Cancel" or IE pops up that download security bar. I'm wondering if there's an alternative solution.
Could we push the download to the user and then only mark records as downloaded when we're sure they've received the right number of bytes? I have to say that I'm struggling with this one and a solution which is as easy for end users as possible would be fantastic.
There isn't any reliable way to do this without a process running on the client which can verify the transfer completed. Of course, the only process we can reasonably expect the user to already have, or be willing to install, is Flash.
Only Flash 10 supports saving files directly to disk as the user requests. (Previous versions had a "shared object" which was kind of like a very large cookie space more than anything else - not for transferring files but saving reusable application data). Read up here for info on how to interact with the end-user's filesystem via Flash 10.
Essentially there is a method call save() which will push data to a location of the user's choosing. The specific location is hidden from your code; for obvious security reasons, you merely push the file into a black box and Flash handles the rest.
The only real bit of info missing here is how to get your file into the Flash player, but anyone with a little Flash experience should have no trouble figuring that out with a few minutes of research. Without Flash experience you should still have it working in under a day.
Rather than simply redirecting the user to the resource that is to be downloaded (there by causing the popup of would you like to download a file) you might try to two things. Push the resource out of a page as a byte array. Once the download has completed redirect the download page to another page. On this page you can then add to your workflow asking if the download went ok or not. Also, if they got this far you could assume (ass-u-me) that it worked. To actually track how far the download got I don't think is doable as you have nothing on the other end monitoring bytes received.
I don't believe there is. If this is necessary you may need to utilize a Silverlight (Or flash) control in conjunction with your application.
Basically the approach with either one would be to open a socket connection to the HTTP url and save it to the appropriate path on the User's drive. Once the download is complete you could have the control generate a hash value from the file and send that back to some ASP page. If the hash value is never submitted or is incorrect you know they didn't finish the file.
Even checking that all the bytes were sent doesn't really guarantee anything:
The user might still cancel the download before saving it, or their browser might crash, etc.
The recipient might not be the user. It might be a proxy server with a virus scanner that decides to block the transfer, etc.

Resources