Hi, I am building an application on AppEngine platform. Whenever a user requests for an invite, the user is sent an email with a link. The user when clicks on the link is presented with a registration page which contains two forms :
1. Custom Registration form 2. Image upload form for a profile picture. This form is integrated with Google Blobstore service. The user fills in the information. When he clicks on the image upload button, he is presented with an overlay containing the image upload form where he chooses and adjusts the image he would like to set as his profile pic. Once finalized, the overlay is closed and the user now clicks on "Complete Registration" button. The controller then makes the entries in the corresponding tables and the user is redirected to his profile page as can be seen from the code below. The code for the custom registration form (controller) is as follows: email_id = request.get_vars['email'] activation_key = request.get_vars['id'] image_error_msg = "" try: # Check if its an already existing user if dal_db(dal_db.auth_user.email==email_id.lower()).select(): raise HTTP(404) else: # Validate the email and activation key check_user = dal_db(dal_db.Signup.email==email_id).select().first() if ((check_user!=None) and (check_user.activation_key!='') and (check_user.activation_key!=None) and (check_user.activation_key==activation_key)): # Define the registration form form = SQLFORM(dal_db.auth_user, fields=['first_name','last_name','location','password'], submit_button='Complete Registration', _id='info', _name='registration' ) form.custom.widget.password['_checkref']='#showpassword' form.custom.widget.password.requires=dal_db.auth_user.password.requires if form.validate(hideerror=True): # Get values from form fields password = form.vars.password first_name = form.vars.first_name last_name = form.vars.last_name location = form.vars.location userFriendsID = request.vars.userFriendsID if (session.profile_image is None) and (session.thumb_image is None): image_error_msg = "Required" return dict(form=form,image_error_msg=image_error_msg) # Create User object new_user = User(email_id.lower(),password,first_name,location,session.profile_image,session.thumb_image) new_user.set_user_extras(last_name) # Define cross transaction options xg_options = db.create_transaction_options(xg=True) # Run the new user insert in transaction registered_id = db.run_in_transaction_options(xg_options,new_user.create_user,dal_db) # Make activation key NULL updated_records = check_user.update_record(activation_key='',activation_ind='Y') # Auto Login user_dict = new_user.__dict__ user_dict['id']=registered_id session.auth = Storage(user=user_dict, last_visit=datetime.now(), expiration=auth.settings.expiration, hmac_key=web2py_uuid()) redirect(URL('user','profile')) elif form.errors: if form.errors.first_name!=None: form.errors.first_name="First Name cannnot be empty" if form.errors.location!=None: form.errors.location="Please tell us where you live" if form.errors.password!=None: form.errors.password="Please provide atleast 6 characters" else: form.errors.first_name="" form.errors.location="" form.errors.password="" else: raise HTTP(404) except (Error, Exception), ex: logger.error("Fatal Error while registering " + str(ex)) raise HTTP(500) return dict(form=form,image_error_msg=image_error_msg) The image upload form code is derived from the source: http://www.web2pyslices.com/slice/show/1388/google-app-engine-blobstore-api-support and is implemented with modifications as: form = SQLFORM(dal_db.blobstore_image, fields=['blob_key'],_name='uploadimage') # Get the dynamic upload_url for blobstore and set the form action upload_url = blobstore.create_upload_url(URL(r=request,f='upload_image')) form['_action']=upload_url (begin, end) = form._xml() form.custom.begin = XML("<%s %s>" % (form.tag, begin)) image_url = "" if request.args and request.args[0] and request.args[0]!='-1': row = dal_db(dal_db.blobstore_image.id==request.args[0]).select().first() if row and row.blob_key: session.image_id = request.args[0] image_url = row.image_url elif request.args and request.args[0]=='-1': image_url="#" blob_info = None if request.vars.blob_key == '': request.vars.blob_key = None if request.vars.blob_key != None: blob_info = blobstore.parse_blob_info(request.vars.blob_key) del request.vars['blob_key'] if form.accepts(request.vars,formname="uploadimage"): row = dal_db(dal_db.blobstore_image.id == form.vars.id).select().first() # If the image has been updated, remove the previous image from blobstore if (blob_info and (row and row.blob_key)): blobstore.delete(row.blob_key) row.update_record(blob_key=None) if blob_info: try: # Check for valid extensions content_type = blob_info.content_type.split('/')[1] if content_type!='jpeg' and content_type!='png': raise Exception("Uploaded image does not have a valid content_type") elif blob_info.size > 1048576: raise Exception("Uploaded image is greater than 1 MB") else: key = blob_info.key() url = get_serving_url(str(blob_info.key())) uploaded_image = images.Image(blob_key=blob_info.key()) uploaded_image.rotate(360) if (blob_info.content_type).split('/')[1]=='jpeg': uploaded_image.execute_transforms(output_encoding=images.JPEG) else: uploaded_image.execute_transforms() if uploaded_image.width < 300 or uploaded_image.height < 300: raise Exception("Image size less than 300x300") session.image_width = uploaded_image.width session.image_height = uploaded_image.height logger.debug(str(session.image_width)) logger.debug(str(session.image_height)) row.update_record(blob_key = key,image_url = url) except (Error,Exception), err: logger.debug("Exception Raised: " + str(err)) blobstore.delete(blob_info.key()) raise HTTP(303,Location= URL(r=request,f='upload_image',args='-1')) raise HTTP(303,Location= URL(r=request,f='upload_image', args=form.vars.id)) elif form.errors: logger.info(str(form.errors)) if blob_info: blobstore.delete(blob_info.key()) raise HTTP(303,Location= URL(r=request,f='upload_image',args='-1')) return dict(form=form,image_url=image_url) In the view the image upload form is included as a component with ajax=False For implementing the ajax functionality for uploading profile image we are using ajaxForm of http://jquery.malsup.com/form/ The code for the .load component is : {{if image_url=="":}} <span id="greetingmsg">Please upload a (JPG,PNG) image of minimum 300x300 px and a maximum size of 5MB</span> {{else:}} <table> <tr> <td><img src="{{=image_url}}" id="selectedphoto"/></td> <td><div id="previewBox"><img src="{{=image_url}}" id="preview"/></div></td> </tr> </table> <span id="greetingmsg"></span> <span id="photocoord"> <input type="hidden" id="x" name="x"/> <input type="hidden" id="y" name="y"/> <input type="hidden" id="w" name="w"/> <input type="hidden" id="h" name="h"/> <a href="#" id="coord">Done</a> </span> {{pass}} {{=form.custom.begin}} {{=form.custom.widget.blob_key}} {{=form.custom.end}} <script language="javascript" type="text/javascript"> $(document).ready(function(){ $('form').ajaxForm({target:'#target'}); $('input[name=blob_key]').change(function(){ $('#greetingmsg').html('Uploading...'); $('#target form').submit(); }); {{if image_url!="":}} $('#selectedphoto').Jcrop({ minSize: [300,300], boxWidth: 440, boxHeight: 330, setSelect: [300, 300, 0, 0 ], aspectRatio: 1, onChange: updatePreview },function(){ // Use the API to get the real image size var bounds = this.getBounds(); boundx = bounds[0]; boundy = bounds[1]; $('#photocoord').show(); $('#photoUpload').css({'margin-left':-($('#photoUpload').width()/2+30)}); }); $('#previewBox').css({width:'300px', height:'300px', overflow:'hidden'}); $('#photoUpload').css({'margin-left':-($('#photoUpload').width()/2+30)}); $('#photocoord a').click(function(){ //$('span.temp').html('Saving Image'); ajax('create_profile_pic', ['x','y','w','h'], ':eval'); return false; }); {{pass}} }); </script> *The Problem:* When the user clicks on "Complete Registration" button, the code redirects to the profile page as we can see in the GAE server logs INFO 2012-06-14 15:43:31,057 dev_appserver.py:2891] "POST /devekayan*/registration/activate?email=sushant.tanej...@gmail.com&id=755047905ed0e8df1d90cfa687ca0f4986d1e946 HTTP/1.1" 303 -* INFO 2012-06-14 15:43:31,242 gaehandler.py:69] **** Request: 149.23ms/150.00ms (real time/cpu time) INFO 2012-06-14 15:43:31,248 recording.py:486] Saved; key: __appstats__:011000, part: 60 bytes, full: 6092 bytes, overhead: 0.000 + 0.005; link: http://localhost:8080/_ah/stats/details?time=1339688611093 INFO 2012-06-14 15:43:31,266 dev_appserver.py:2891] "GET /devekayan*/user/profile HTTP/1.1" 200 -* INFO 2012-06-14 15:43:31,322 dev_appserver.py:2891] "GET /devekayan/static/js/jquery.js?_=1339688611296 HTTP/1.1" 200 - INFO 2012-06-14 15:43:31,460 dev_appserver.py:2891] "GET /devekayan/static/js/web2py.js?_=1339688611425 HTTP/1.1" 200 - INFO 2012-06-14 15:43:31,508 dev_appserver.py:2891] "GET /devekayan/static/js/jquery.easing.js?_=1339688611466 HTTP/1.1" 200 - INFO 2012-06-14 15:43:31,547 dev_appserver.py:2891] "GET /devekayan/static/js/jquery.form.js?_=1339688611518 HTTP/1.1" 200 - But on the client side nothing happens. (i.e. the user remains on the registration page itself). The profile page is not loaded at all. The problem started occurring only after we integrated the blobstore service. Earlier we were storing images in datastore and everything was working fine. I have reproduced the problem in production and on both Chrome and Firefox browers. Can anyone tell me what might be the problem ? Thanks, Sushant Taneja