2

I have a multi-step form inspired by this railcast that has 3 file upload images. However when I upload an image I receive an error can't dump File.

From other questions in SO I understand that saving a file uploads in the session doesn't work so I need ot use something like this:

   unless @post.valid?
      @post.assets.first.attachment.clear
      @post.assets.first.attachment.queued_for_write.clear
    end

This however doesn't seem to work. Should I look through the three file uploads and clear them every time? How can I avoid this error?

Here is my create function:

    session[:post_params].deep_merge!(params[:post]) if params[:post]
    session[:duration] = params[:post_duration] if params[:post_duration]


    @post = Post.new(session[:post_params])
    @post.current_step = session[:post_step]

   unless @post.valid?
      logger.info("attachment " +  @post.assets.first.attachment.inspect)
      @post.assets.first.attachment.clear
      @post.assets.first.attachment.queued_for_write.clear
    end


    if @post.valid?
      if params[:back_button]
        @post.previous_step
      elsif @post.last_step?
        if @post.all_valid?
          ...
          session[:post_step] = session[:post_params] = nil
          redirect_to @post and return
        end
      else
        @post.next_step
      end  

    session[:post_step] =  @post.current_step
    end

    if @post.new_record?
         render "new"
    end
  end

My asset model

class Asset < ActiveRecord::Base
  # attr_accessible :title, :body

 belongs_to :post
 attr_accessible :attachment
 has_attached_file :attachment, :styles => { :medium => "600x600>", :small => "200x200>", :thumb => "100x100>" }, 
 :default_url => "no_image_:style.jpg"
end
Ayrad
  • 3,996
  • 8
  • 45
  • 86
  • I don't have much experience with this in particular, so you may gain some insight from this [StackOverflow post](http://stackoverflow.com/questions/5876714/multi-step-form-in-rails-3-with-paperclip-attachments/8079113#8079113) – Richard Peck Jan 31 '14 at 09:39
  • @RichPeck that is indeed where I found the suggestion for clearing the image object – Ayrad Jan 31 '14 at 09:44
  • it may help http://stackoverflow.com/questions/7079999/paperclipnotidentifiedbyimagemagickerror-image-is-not-recognized-by-the-ident/16933264#16933264 – Nithin Feb 12 '14 at 10:27

1 Answers1

1

The problem is that you cannot store a File into the session object since it has to be Marshaled and that is not supported. As I see it you have three possible solutions:

  1. The easy way out of this would be to add the image upload part at the last step of you wizard. That way you don't need to save the last part of information in the session but rather directly in your object. Just make sure that you skip the session save on the last step or you take out the file params before storing them to your session with something like

    params[:post].except(:assets)
    
  2. The second solution is much trickier. What you can do is every time your controller tries to save a model you persist the attachments to the disk at a known place with a unique name. Now instead of storing the file to the session you will be storing the local file names that you just created (you still need something like the except from #1 to avoid the exception). Upon save you will basically restore the files from the server disk as specified in the session params. To keep things clean you need a cron job that would delete old files (e.g. any file saved a week ago). You can use whenever for that.

    Tip: If you choose the above solution and your attachments are a separate model, as it is seems, you can actually save the "temp" assets without an associated post_id. Then instead of file names you will handle unique database ids ;)

  3. Lastly if your business logic (and your nerves) allow it, you can consider persisting your model in the database on every step, probably with a flag meaning that it is partially saved. That way you will not need the use of a session but you are going to have to deal with many conditionals (in your validations, in your scoping, in your associations ...) and of course you still need that cron job.

Nikos
  • 1,052
  • 5
  • 7
  • Good suggestions. I wish solution 1 worked but having my image uploads at the last step (payment) would not be logical. I'm investigating solution 2 which might be complicated since I'm using heroku. – Ayrad Feb 09 '14 at 11:32
  • I think you might have confused the usage of models and the multi-step form. You don't need to match all your form steps with one model. I am not sure what your business logic is but it could also make sense to create a model through the first few steps and at the last step where you get the payment just pass the reference of the created object `id` and generate a different model associated with the other one. Not sure if that was clear :) – Nikos Feb 09 '14 at 11:41
  • I am indeed a bit confused. Could you clarify? It looks like the images are uploaded into a param called assets_attributes so I remove it from the session like this: session[:post_params].deep_merge!(params[:listing].except(:assets_attributes)) if params[:post]. How can I save the assets separately (the uploaded images) and add them at the last step to the post? – Ayrad Feb 10 '14 at 20:14
  • If you are referring to my previous comment, I meant that if for example you have 4 steps you could split them into 3+1. In the first three you do what you are already doing and in the step #3 you get the images and save them along with the data from #1,#2 to a model. Then you redirect the user to a different action with the model id you just saved as a param. So in the final step you save a different model and associate it with the one you created in steps #1-#3. All the above could be non applicable to your business logic. Does it make more sense now? – Nikos Feb 10 '14 at 20:23
  • Thank you for the clarification I understand the logic and uploading the images right before the first model save so it doesn't need to be stored in the session. I am just not sure that it fit this particular wizard since the whole form corresponds to one model and a lot of things are happening during the save for the model. – Ayrad Feb 10 '14 at 20:38