moiristo / deep_cloneable

This gem gives every ActiveRecord::Base object the possibility to do a deep clone that includes user specified associations.
MIT License
786 stars 88 forks source link

Don't copy multiple files #103

Closed afuno closed 5 years ago

afuno commented 5 years ago

There is a Rails 6.1.6.1 application with CarrierWave.

There is a deep copy:

@new_blog = @blog.deep_clone(include: [:blogs_tags, posts: { pages: { blocks: %i[uploads] } }]) do |original, copy|
    # ...
    elsif original.is_a?(Upload) && copy.is_a?(Upload)
        copy.file = original.file
    end
    # ...
end

The problem is in the presence of the uploads table. If the image is one, then everything is fine. If there is more than one image, then an error:

{"posts":["is invalid"]}

What could be the problem?

afuno commented 5 years ago

It works if add this: validate: false. But I don't understand why this is happening. For some reason validators from AR work strangely for copying.

I do not use anything complicated in the models. Standard (for example):

# uploads
validates :file, presence: true
moiristo commented 5 years ago

Hello,

Can't really say at this point. You should first find out which validation is failing; it is probably something nested within posts. Something like:

@new_blog.valid?
invalid_pages = @new_blog.posts.pages.reject(&:valid?)
puts invalid_pages.errors.full_messages.to_sentence
invalid_blocks = invalid_pages.flat_map(&:blocks).reject(&:valid?)
puts invalid_blocks.errors.full_messages.to_sentence
invalid_uploads = invalid_blocks.flat_map(&:uploads).reject(&:valid?)
puts invalid_uploads.errors.full_messages.to_sentence

Maybe this will help you to find out what's going on..

afuno commented 5 years ago

@moiristo

invalid_posts = @new_post.posts.reject(&:valid?)
puts invalid_posts.flat_map { |l| l.errors.full_messages.to_sentence }.to_json

invalid_pages = invalid_posts.flat_map(&:pages).reject(&:valid?)
puts invalid_pages.flat_map { |p| p.errors.full_messages.to_sentence }.to_json

invalid_blocks = invalid_pages.flat_map(&:blocks).reject(&:valid?)
puts invalid_blocks.flat_map { |b| b.errors.full_messages.to_sentence }.to_json

invalid_uploads = invalid_blocks.flat_map(&:uploads).reject(&:valid?)
puts invalid_uploads.flat_map { |u| u.errors.full_messages.to_sentence }.to_json
# => ["Pages is invalid","Pages is invalid","Pages is invalid","Pages is invalid","Pages is invalid","Pages is invalid","Pages is invalid"]

# => ["Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid","Blocks is invalid"]

# => ["Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid","Uploads is invalid"]

# => ["File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank","File can't be blank"]

🤔🤔🤔

I don't understand why this error occurs. Uploading images to the server is working. Duplication works if one image (but not 21 as in this example).

moiristo commented 5 years ago

Can you check if the block is executed for every upload object? so, in the block, add something like


if original.is_a?(Upload)
  puts original.id
  puts copy.is_a?(Upload)
end
afuno commented 5 years ago

Yes. The logs have it all.

moiristo commented 5 years ago

I don't know in that case. deep_cloneable seems to work as intended as it properly dups the uploads object and calls the block for every dup. Maybe something goes with the assignment of the file?

I'm closing this, feel free to reopen it if you think it is a deep_cloneable issue after all.

afuno commented 5 years ago

@moiristo I forgot to show you the model code. Maybe this is important.

class Upload < ApplicationRecord
  belongs_to :section,
             polymorphic: true,
             optional: true

  validates :file, presence: true

  validates :position,
            numericality: {
              only_integer: true,
              greater_than_or_equal_to: 0
            }

  mount_uploader :file, AllFilesUploader

  default_scope { order(position: :asc) }

  def title
    file_identifier.delete(".#{extension}")
  end

  def extension
    file_identifier.split('.').last
  end
end

But the error still occurs because of this:

validates :file, presence: true
moiristo commented 5 years ago

Maybe there is an underlying carrierwave error, causing the file to be blank? See here