How to upload a photo from a Rails cache hash? - ruby-on-rails

I'm quite new with Rails and I'm trying to implement a multistep form in my app for creating a new instance of my User model (devise gem).
I use wicked gem and I've chosen a cache persistence and an ID/Key-in-Session as strategies to handle it.
For now, everything works well until I come across the avatar step in my form which is my last one (a #user has_one_attached :avatar).
When I try to submit my form, I got the below issue raising from that line: Rails.cache.write(session.id, user_attrs)
TypeError in Users::UserStepsController#update
can't dump File
Here my user_attrs when I submit my picture:
{"messenger_id"=>"1234567890123456",
"form_step"=>:profile_picture_step,
"first_name"=>"John",
"last_name"=>"Doe",
"email"=>"john#gmail.com",
"password"=>"1234",
"password_confirmation"=>"1234",
"avatar"=>#<ActionDispatch::Http::UploadedFile:0x00007fbdc4cdf418
#tempfile=#<Tempfile:/var/folders/m_/8ln6gczs1ns1gnn53p6vskwr0000gn/T/RackMultipart20210527-5416-uy59kl.png>,
#original_filename="Screenshot 2021-05-26 at 20.34.43.png", #content_type="image/png",
#headers="Content-Disposition: form-data; name=\"user[avatar]\"; filename=\"Screenshot 2021-05-26 at 20.34.43.png\"\r\nContent-Type: image/png\r\n">}
It seems Rails.cache.write is not able to write this avatar object, am I right? If so, is there a way to fix it?
Thank you for your help!

Related

Persisting flash when a form is submitted multiple times

Background: I have essentially a multiple choice quiz. When a user submits a form, update scores their answer, chooses a new question, puts a message in the flash, and redirects back to the show action. show displays the message and the new question.
The immediate problem is that if they submit the form twice, update gets called twice. The first time scores their answer for the question they were given. The second time scores their answer for the question that was just now selected, which they haven't seen yet. So then they get redirected with a message saying something like "wrong! The answer is Spain, not Italy" When they had been choosing between Hydrogen and Helium.
So my first solution to this is to include a question_id field in the submitted form. If the submitted id isn't the id of the question that was asked, just ignore this request. This works for keeping track, but the message that was stored in the flash is lost.
So I've tried adding flash.keep if the ids don't match. My thinking is that one update will set the flash, and then the next request received will be the second update. But the flash is still getting lost. It seems that the second update doesn't start with a flash at all, which confuses me.
So my questions are: is there a better way to handle this problem? And if not, why is the flash disappearing?
update looks something like this (some lines omitted):
def update
game = current_user.credence_game
question = game.current_question
if params[:question_id].to_i == question.id
given_answer = params[:answer_index].to_i
credence = params[:credence].to_i
correct, score = question.score_answer(given_answer, credence)
game.score += score
game.new_question
game.save
flash[:correct] = correct
flash[:score] = score
flash[:message] = question.answer_message(given_answer)
else
flash.keep
end
redirect_to action: 'show'
end
If I add a p flash line just before redirect_to, the server spits out this:
#<ActionDispatch::Flash::FlashHash:0x007f2a8431b4a0 #used=#<Set: {}>, #closed=false, #flashes={:correct=>false, :score=>-32, :message=>"Incorrect. The right answer is White River (Arkansas) (1102km) versus Yellowstone River (1080km)."}, #now=nil>
Started PUT "/credence" for 127.0.0.1 at 2014-08-17 15:20:16 +0100
Processing by CredenceController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"EiqXDoFy77nmdKOE4YkHOeEFg4DvB5zdgFi98ynNCx0=", "question_id"=>"52", "credence"=>"60", "answer_index"=>"1", "commit"=>"60%"}
<Model stuff>
Redirected to http://localhost:3000/credence
Completed 302 Found in 667ms
#<ActionDispatch::Flash::FlashHash:0x000000059864f8 #used=#<Set: {}>, #closed=false, #flashes={}, #now=nil>
Started PUT "/credence" for 127.0.0.1 at 2014-08-17 15:20:18 +0100
Processing by CredenceController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"EiqXDoFy77nmdKOE4YkHOeEFg4DvB5zdgFi98ynNCx0=", "question_id"=>"52", "credence"=>"70", "answer_index"=>"1", "commit"=>"70%"}
<Model stuff, just loading the game and the question>
Redirected to http://localhost:3000/credence
Completed 302 Found in 421ms
Started GET "/credence" for 127.0.0.1 at 2014-08-17 15:20:19 +0100
Processing by CredenceController#show as HTML
<Model stuff>
Rendered layouts/_messages.html.erb (400.4ms)
Completed 200 OK in 963ms (Views: 776.4ms | ActiveRecord: 27.7ms)
<GET requests for CSS, images, etc.>
So it does seem like the first request after the flash is set, is the one where I'm calling flash.keep, but it still doesn't have the flash.
Edit: I'm realising the problem is likely that I'm using CookieStore. The first request doesn't get a chance to set cookies before the second request is sent. Using the session instead of flash would have the same issue.
A simple solution here, that I don't much like, would be to simply disable the forms with javascript onsubmit. A more complicated one would be: when the question ids don't match, look up the answer that the user gave for the submitted question id, and set the flash appropriately without changing the score.
Any alternatives?

Captcha with Multipart Form Rails

I have a multipart form that I need a captcha for at the end. Essentially, a user is allowed to create/update a draft but not submit it for admin review until everything is done. There is a captcha meant for the last submission but the problem is that when I add it to the form, I can't use any of the other submit buttons because the captcha isn't filled out. Is there any way around this?
I'm using simple_captcha and Rails 3.2.
Thanks!
I haven't used simple_captcha before, but seems like you are doing #object.save_with_captcha in every case. You have multiple options to solve this, but one i came up with is:
In the controller, verify if all the fields (mandatory only i guess) are filled, and if they are, then save your object using #object.save_with_captcha, otherwise do the usual #object.save which wont trigger the captcha validation. Something like this:
def create
#object = MyObject.new(params[:my_object])
if #object.has_mandatory_fields_filled?
#object.save_with_captcha
else
#object.save
end
end
In the has_mandatory_fields_filled? method you would check that all the mandatory fields of your form are not empty/nil etc.

Paperclip - Image attributes not passed in the query INSERT

I have all the default settings from paperclip's website. When I create a new application and put the settings in, once I save my model, the 'photo' paperclip attribute gets saves nicely, all is fine (here is the SQL INSERT sample):
"photo"=>#<ActionDispatch::Http::UploadedFile:0x007f990a3d92d0
#original_filename="Screen Shot 2011-10-21 at 6.02.56 AM.png",
#content_type="image/png", #headers="Content-Disposition: form-data;
name=\"event[photo]\"; filename=\"Screen Shot 2011-10-21 at 6.02.56
AM.png\"\r\nContent-Type: image/png\r\n"
and I get:
[paperclip] Saving attachments
Now in my app other app where I use Devise and Cancan, I have the exact same Paperclip setting, I do get the
[paperclip] Saving attachments.
But, It does not save the 'photo' and don't see the photo attributes getting defined at all.
Now I've seen a similar post that gets solved adding
attr_accessible photo
to the model, and I did that, and still it's not working.
I've been wasting so many hours on this, sometimes I feel like I should have just created my own image upload...
Any idea? Thx!
and by the way. Same issue on a simple scaffold object where I add
attr_accessible :photo
If you're using a framework like jQuery Mobile or some sort of AJAX/PJAX mechanism, your uploads will be lost as POST in Ajax, since JS cannot read your local files...
You'll have to use some uploadify-like plugin or submit your form the "regular" way.
Edit:
To make things clear, the easiest way will be to add data-ajax="false" as a form attribute. In Rails 3, using the form helper, you'd write something along those lines:
<%= form_for (#my_object, html: {data: {ajax: false}}) do |f| %>
...
<% end %>

Finding form fields in a Rails POST request

I'm using a plain old HTML form to send a post request to a rails app. Inside the app I would like to grab some of the input fields. I'm having trouble finding them inside the request.
Trying this:
logger.debug "Request Headers #{request.headers.inspect}"
Spits out a massive amount of data but I cannot find my form fields in there. Does anyone know where I can find them?
You can grab the request parameters submitted using:
logger.debug params.inspect
That will show all the form data submitted.

Devise + OmniAuth - How to capture a FB Connect on registration

I'm building a registration flow that allows a user to FB Connect to pre-populate the registration form. I'm also then capturing fb_uuid and fb_access_token.
When the user submits the registration form that is submitted as follows:
Started POST "/users" for 127.0.0.1 at Mon Jul 11 17:44:40 -0700 2011
Processing by Devise::RegistrationsController#create as HTML
Parameters: {"commit"=>"Create my account", "fb_access_token"=>"XXXXXXXXXXX", "authenticity_token"=>"XXXXXXXXXX", "utf8"=>"✓", "user"=>{"remember_me"=>"0", "lname"=>"NNNNNN", "fname"=>"BBBBBB", "password"=>"[FILTERED]", "email"=>"dadad#google.com"}, "fb_uuid"=>"50123190"}
notice the fb_access_token, fb_uuid
In the Registration#Create, how can I capture those values and populate the Authentications table? Do I have to override devise?
Thansk
Although you may not need this right now, here's a blog post that you can use to solver your problem:
Devise on rails: Prepopulating form data
You can use the method described there to capture and process the data you need.
Hope it helps.
You can use the koala gem to pull those fb parameters from the facebook cookie after the user does a FB_Connect. Take a look at this:
https://github.com/arsduo/koala/wiki/Koala-on-Rails
I'm curious on why you aren't creating the user right after the FB_Connect which is the more common and intuitive user experience, as opposed to just prepoulating the registration form.
Like this:
https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview

Resources