Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Append more files #1545

Closed
fabrouy opened this issue Jan 17, 2015 · 16 comments
Closed

Append more files #1545

fabrouy opened this issue Jan 17, 2015 · 16 comments

Comments

@fabrouy
Copy link

fabrouy commented Jan 17, 2015

Hi guys,

This is what I have:

class Foo < ActiveRecord::Base
    mount_uploaders :images, FooUploader
end

:images is stored as json in the DB.

Also I am sending files in chunks using dropzone, so for example If I drop two images at the same time they get stored together in the json field.
The problem comes when I want to drop another image after waiting a while, I would like to "append" this new image to the other two in an update action.

I would like to do something like this:

u = User.find(xxx)
u.images << params[:files] # Assign an array of files like this
u.save!

Is this possible to accomplish?

@Uelb
Copy link

Uelb commented May 16, 2015

@fabrouy, It think it seems odd to use the << method to add an array to another. Something like

u = User.find(xxx)
u.images += params[:files]
u.save!

is more intuitive. (It may already work, I have no idea).

@evg2108
Copy link

evg2108 commented May 30, 2015

Hello.

I have a question. When i try do like this

u = User.find(xxx)
u.images += params[:files]
u.save!

then in tmp directory created all files which have already been in the array u.images + files from params[:files]. I use generation uniq file names, and when i add new files, all old files regenerated and all their names are changed. What can I do to avoid this?

Sorry for my english

@thomasfedb
Copy link
Contributor

@Uelb In fact << is a more sensible operator than += as it implies appending to an existing collection, rather than assigning a new summation of the existing and new collections.

@Uelb
Copy link

Uelb commented Dec 10, 2015

<< implies appending a single element to a collection whereas += appends a collection to another one.

[1,2,3] << [4,5,6] # => [1,2,3, [4,5,6]]
[1,2,3] += [4,5,6] # => [1,2,3,4,5,6]

@thomasfedb
Copy link
Contributor

@Uelb this is true, so in fact the right API would be #concat

# Using << appends a single item to an existing array.
arr = [1,2,3] #=> [1, 2, 3] 
arr.object_id #=> 10564640 
arr << 4 #=> [1, 2, 3, 4] 
arr.object_id #=> 10564640

# Using += creates a new array.
arr = [1,2,3] #=> [1, 2, 3] 
arr.object_id #=> 11147760 
arr += [4] #=> [1, 2, 3, 4] 
arr.object_id #=> 11277560

# Using #concat can append multiple items.
arr = [1,2,3] #=> [1, 2, 3] 
arr.object_id #=> 11329480 
arr.concat([4]) #=> [1, 2, 3, 4] 
arr.object_id #=> 11329480 

@Uelb
Copy link

Uelb commented Dec 10, 2015

I totally agree with you :D !
concat would be the right way to go

@evg2108
Copy link

evg2108 commented Dec 23, 2015

concat is not work. When i do this

class Author < ActiveRecord::Base
  mount_uploaders :photos, AuthorPhotoUploader
  # ...
end
author.photos.concat(get_photos)
author.save

i get error:

NoMethodError (undefined method `identifier' for #ActionDispatch::Http::UploadedFile:0x0000000a727950)

@thomasfedb
Copy link
Contributor

Hi @evg2108, I never said that concat would work, only that it might be the way that it should work.

@evg2108
Copy link

evg2108 commented Dec 23, 2015

But I still don't know how do this right. Do you have any suggestion?

@bastengao
Copy link

When will be mount_uploaders feature ready for release ? I see implementation is already in master.

@juanbrein
Copy link

juanbrein commented Aug 21, 2016

I managed to append images. My use case is a post model with an images field. The code changes are:

post.rb

 def append_images post_params                          
   appended_images = post_params[:images].map do |image|
     uploader = PostImageUploader.new(self)             
     uploader.store! image                              
     uploader
   end
   self.images = self.images + appended_images          
 end

post_controller.rb

  def update                                                                       
    respond_to do |format|                                                         
      @post.append_images post_params if post_params[:images]                               
      if @post.update(post_params_without_images)                                  
        format.html { redirect_to @post, notice: 'Post was successfully updated.' }
        format.json { render :show, status: :ok, location: @post }                 
      else                                                                         
        format.html { render :edit }                                               
        format.json { render json: @post.errors, status: :unprocessable_entity }   
      end                                                                          
    end                                                                            
  end                                                                              

post_controller.rb (private)

    def post_params_without_images                                                                   
      params.require(:post).permit(:title, :body, :published)   
    end                                                                                              

Hope it helps

@bastengao
Copy link

@juanbrein Thank you. My solution is Post has many Image model and use accepts_nested_attributes_for.

class Post < ActiveRecord::Base
    has_many :images
    accepts_nested_attributes_for :images, reject_if: :all_blank, allow_destroy: true
end

class Image < ActiveRecord::Base
  mount_uploader :file, ImageUploader
end

class PostsController < ApplicationController

  private 
  def post_params
    params.require(:post).permit(:title, :imagess_attributes => [:id, :file, :_destroy]}
  end
end

But these solutions are little complicated. I really hope mount_uploaders is available in new release.

@evg2108
Copy link

evg2108 commented Sep 1, 2016

@juanbrein when you append new images all old images will be re-processed. And appending every new image will be slower.

I change your code:

in model

def append_images post_params                          
   appended_images = post_params[:images].map do |image|
     uploader = PostImageUploader.new(self)             
     uploader.store! image                              
     uploader
   end
    self[:images] ||= []
    self[:images] += appended_images.map{ |uploader| uploader.file.filename }
end

in controller

   @post.append_images post_params if post_params[:images]
   @post.save

@unmanbearpig
Copy link

unmanbearpig commented Jan 10, 2017

I've written a test to demonstrate the issue unmanbearpig@972945a

I think the biggest problem is not that it's not possible to use << on images but that the error is very confusing, it crashes on save! instead of << call, so it took me some time to figure out what was going on. I think we could at least freeze theimages array to make it crash on << and make it obvious that it's not supported. Or maybe we could use an enumerable object that would support it by tracking changes to it, instead of a plain Ruby array.
I can work on a PR if someone would point me in the right direction.

@60mm
Copy link

60mm commented Aug 31, 2018

I solved this issue by adding this to the model with the images attached. I am a novice coder so I can't promise it is the fastest, but it does work. I have the images stored as JSON.

before_validation { self.previous_images }
before_save { self.add_previous_images }

def previous_images
  if self.images
    @images = self[:images]
  end
end  

def add_previous_images
  if defined?(@images)
    @images.each do |a|
      if !self[:images].include?(a)
        self[:images] << a
      end	
    end	
  end	
end

@mshibuya
Copy link
Member

Closed by #2401.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants