问题
I want to build 3 step user registration with avatar uploading on 2nd step. So i follow Ryan Bates's guide http://railscasts.com/episodes/217-multistep-forms . I'm using CarrierWave gem to handle uploads. But it seems like i can't store uploaded file info in user session (i'm getting can't dump File error). I use following technique in controller
if params[:user][:img_path]
@uploader = FirmImgUploader.new
@uploader.store!(params[:user][:img_path])
session[:img] = @uploader
params[:user].delete(:img_path)
end
It actually helps. But when i upload forbidden file type everything's crashes on this line
@uploader.store!(params[:user][:img_path])
with this error
CarrierWave::IntegrityError in UsersController#create
You are not allowed to upload "docx" files, allowed types: ["jpg", "jpeg", "gif", "png"]
instead of normal form validation error.
How can i solve this problem ? Thanks !
回答1:
Actually I solved my problem. Here's working code for multistep forms with file uploading using carrierwave
if params[:user][:img_path]
@uploaded = params[:user][:img_path]
params[:user].delete(:img_path)
end
session[:user_data].deep_merge!(params[:user]) if params[:user]
@user = User.new(session[:user_data])
if @uploaded
# here how validation will work
@user.img_path = @uploaded
end
@user.current_stage = session[:register_stage]
if @user.valid?
if @user.last_stage?
@user.img_path = session[:img] if @user.last_stage?
@user.save
else
@user.next_stage
end
# now we can store carrierwave object in session
session[:img] = @user.img_path
session[:register_stage] = @user.current_stage
end
回答2:
This may be a little late for the OP, but hopefully this helps someone. I needed to store an uploaded image in the user's session (again for a multi-step form), and I too started with Ryan's Railscast #217, but the app quickly evolved beyond that. Note that my environment was Rails 4 on Ruby 2, using Carrierwave and MiniMagick, as well as activerecord-session_store, which I'll explain below.
I believe the problem that both OP and I had was that we were trying to add all of the POST params to the user's session, but with a file upload, one of the params was an actual UploadedFile object, which is way to big for that. The approach described below is another solution to that problem.
Disclaimer: As is widely noted, it's not ideal to store complex objects in a user's session, better to store record identifiers or other identifier data (e.g. an image's path) and look up that data when it's needed. Two major reasons for this keeping the session and model/database data in sync (a non-trivial task), and the default Rails session store (using cookies) is limited to 4kb.
My Model (submission.rb):
class Submission < ActiveRecord::Base
mount_uploader :image_original, ImageUploader
# ...
end
Controller (submissions_controller.rb):
def create
# If the submission POST contains an image, set it as an instance variable,
# because we're going to remove it from the params
if params[:submission] && params[:submission][:image_original] && !params[:submission][:image_original].is_a?(String)
# Store the UploadedFile object as an instance variable
@image = params[:submission][:image_original]
# Remove the uploaded object from the submission POST params, since we
# don't want to merge the whole object into the user's session
params[:submission].delete(:image_original)
end
# Merge existing session with POST params
session[:submission_params].deep_merge!(params[:submission]) if params[:submission]
# Instantiate model from newly merged session/params
@submission = Submission.new(session[:submission_params])
# Increment the current step in the session form
@submission.current_step = session[:submission_step]
# ... other steps in the form
# After deep_merge, bring back the image
if @image
# This adds the image back to the Carrierwave mounted uploader (which
# re-runs any processing/versions specified in the uploader class):
@submission.image_original = @image
# The mounted uploader now has the image stored in the Carrierwave cache,
# and provides us with the cache identifier, which is what we will save
# in our session:
session[:submission_params][:image_original] = @submission.image_original_cache
session[:image_processed_cached] = @submission.image_original.url(:image_processed)
end
# ... other steps in the form
# If we're on the last step of the form, fetch the image and save the model
if @submission.last_step?
# Re-populate the Carrierwave uploader's cache with the cache identifier
# saved in the session
@submission.image_original_cache = session[:submission_params][:image_original]
# Save the model
@submission.save
# ... render/redirect_to ...
end
end
My uploader file was mostly stock with some custom processing.
Note: to beef up sessions, I'm using activerecord-session_store, which is a gem that was extracted from the Rails core in v4 that provides a database-backed session store (thus increasing the 4kb session limit). Follow the documentation for installation instructions, but in my case it was pretty quick and painless to set it and forget it. Note for high-traffic users: the leftover session records don't seem to be purged by the gem, so if you get enough traffic this table could potentially balloon to untold numbers of rows.
来源:https://stackoverflow.com/questions/10355152/multi-step-form-with-image-uploader