Sending files to a Rails JSON API

后端 未结 3 1073
孤城傲影
孤城傲影 2020-12-23 10:02

I know there are questions similar to this one, but I\'ve not found a good answer yet. What I need to do is send a description of an object to one of my create methods, whic

相关标签:
3条回答
  • 2020-12-23 10:24

    TomJ gave a good answer, but at least in Rails 3/Ruby 1.9 there are some minor holes.

    First, don't attempt to call [] on what might be an UploadedFile object in your params object. Make sure you check that it .is_a?(Hash) first, for example.

    Also, make sure you tempfile.rewind() after you write, otherwise you'll get files with 0 length.

    The :original_filename key in the parameters to the constructor of UploadedFile is unnecessary/unused. On the other hand, you may want to provide a :type key. An easy way to find the value for type is mime_type = Mime::Type.lookup_by_extension(File.extname(original_filename)[1..-1]).to_s

    Here is a version with the changes applied:

    # POST /pictures
    # POST /pictures.json
    def create
    
      #check if file is within picture_path
      if params[:picture][:picture_path].is_a?(Hash)
        picture_path_params = params[:picture][:picture_path]
        #create a new tempfile named fileupload
        tempfile = Tempfile.new("fileupload")
        tempfile.binmode
        #get the file and decode it with base64 then write it to the tempfile
        tempfile.write(Base64.decode64(picture_path_params["file"]))
        tempfile.rewind()
    
        mime_type = Mime::Type.lookup_by_extension(File.extname(original_filename)[1..-1]).to_s
        #create a new uploaded file
        uploaded_file = ActionDispatch::Http::UploadedFile.new(
          :tempfile => tempfile,
          :filename => picture_path_params["filename"],
          :type => mime_type) 
    
        #replace picture_path with the new uploaded file
        params[:picture][:picture_path] =  uploaded_file
      end
    
      @picture = Picture.new(params[:picture])
      respond_to do |format|
        if @picture.save
          format.html { redirect_to @picture, notice: 'Picture was successfully created.' }
          format.json { render json: @picture, status: :created, location: @picture }
        else
         format.html { render action: "new" }
         format.json { render json: @picture.errors, status: :unprocessable_entity }
       end
     end
    

    end

    0 讨论(0)
  • 2020-12-23 10:33

    There is an awesome gem for this purpose if you are using carrierwave

    https://github.com/lebedev-yury/carrierwave-base64

    0 讨论(0)
  • 2020-12-23 10:46

    I was actually having a terrible time with this question yesterday to do something very similar. In fact, I wrote the question: Base64 upload from Android/Java to RoR Carrierwave

    What it came down to was creating that uploaded image object in the controller and then injecting it back into the params.

    For this specific example, we are taking a base64 file (which I assume you have, as JSON doesn't support embeded files) and saving it as a temp file in the system then we are creating that UploadedFile object and finally reinjecting it into the params.

    What my json/params looks like:

    picture {:user_id => "1", :folder_id => 1, etc., :picture_path {:file => "base64 awesomeness", :original_filename => "my file name", :filename => "my file name"}}
    

    Here is what my controller looks like now:

      # POST /pictures
      # POST /pictures.json
      def create
    
        #check if file is within picture_path
        if params[:picture][:picture_path]["file"]
             picture_path_params = params[:picture][:picture_path]
             #create a new tempfile named fileupload
             tempfile = Tempfile.new("fileupload")
             tempfile.binmode
             #get the file and decode it with base64 then write it to the tempfile
             tempfile.write(Base64.decode64(picture_path_params["file"]))
    
             #create a new uploaded file
             uploaded_file = ActionDispatch::Http::UploadedFile.new(:tempfile => tempfile, :filename => picture_path_params["filename"], :original_filename => picture_path_params["original_filename"]) 
    
             #replace picture_path with the new uploaded file
             params[:picture][:picture_path] =  uploaded_file
    
        end
    
        @picture = Picture.new(params[:picture])
    
        respond_to do |format|
          if @picture.save
            format.html { redirect_to @picture, notice: 'Picture was successfully created.' }
            format.json { render json: @picture, status: :created, location: @picture }
          else
            format.html { render action: "new" }
            format.json { render json: @picture.errors, status: :unprocessable_entity }
          end
        end
      end
    

    The only thing left to do at this point is to delete the tempfile, which I believe can be done with tempfile.delete

    I hope this helps with your question! I spent all day looking for a solution yesterday, and everything I have seen is a dead end. This, however, works on my test cases.

    0 讨论(0)
提交回复
热议问题