Multi step form with image uploader

十年热恋 提交于 2021-02-07 02:58:56

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!