Dev
Dev

Reputation: 467

Rails 5 carrierwave gem: add more images and remove a single one

I have installed the carrierwave gem on my rails app and also I have implemented this. The only alteration I made was the form:

<div class="container">

  <div class="panel panel-default">
    <div class="panel-body">
      <div class="text-center">
        <% unless current_store.account.images.blank? %>
        <% @account.images.each_with_index do |image, index| #grab the index %>
          <div class="img-thumbnail">
            <%= image_tag(image.url(:mini)) %>
            <br><%= link_to t("store_item_edit_2"), remove_images_path(@account, index),
                            data: { confirm: I18n.t("store_item_edit_3") },
                            :method => :delete %></div>

        <% end %>
        <% end %>


    <% unless @account.blank? %>
    <%= form_for @account, url: create_image_path, :html => {:id => "form"}, method: :post do |form| %>
      <% if @account.errors.any? %>
        <div class="centerList">
          <div id="error_explanation">
            <h2><%= pluralize(account.errors.count, "error") %> <%= t 'store_item_edit_4' %></h2>
            <% @account.errors.full_messages.each do |message| %>
              <li><%= message %></li>
            <% end %>
          </div>
        </div>
      <% end %>
    </div>
    </div>
  </div>
            <div class="form-group">
              <div class="pull-left">
                <label class="btn btn-primary"><%= t 'store_item_edit_5' %><span style="display:none;">
         <%= form.file_field :images, multiple: true, id: "uploads" %></span></label>
                <%= form.submit '', :style => "display: none;" %>
          <% end %>
        <% end %>
    </div>
  </div>
</div>

<script>
document.getElementById("uploads").onchange = function() {
    document.getElementById("form").submit();
};
</script>

All works well, I can upload and view the images! The only problem is when I uploaded new images the old ones get deleted.

I added an images column to the accounts table

  create_table "accounts", force: :cascade do |t|
    t.string "images", default: [], array: true
  end

I even tried the following skip callback but that didn't work also:

class Account < ApplicationRecord
  mount_uploaders :images, AttachmentUploader
  skip_callback :commit, :after, :remove_previously_stored_avatar, :on=> :update, raise: false
end

this is my image controller:

class ImagesController < ApplicationController
  before_action :set_image

  def add_images
    render :template => 'accounts/add_images'
  end

  def create
    add_more_images(images_params[:images])
    flash[:error] = "Failed uploading images" unless @account.save
    redirect_back(fallback_location: root_path)
  end

  def destroy
    remove_image_at_index(params[:id].to_i)
    flash[:error] = "Failed deleting image" unless @account.save
    redirect_back(fallback_location: root_path)
  end

  private

  def set_image
   @account = Account.find(params[:id])
  end

  def add_more_images(new_images)
    @account = Account.find(params[:id])
    images = @account.images
    images += new_images
    @account.images = images
  end

  def remove_image_at_index(index)
    remain_images = @account.images # copy the array
    deleted_image = remain_images.delete_at(index) # delete the target image
    deleted_image.try(:remove!) # delete image from S3
    @account.images = remain_images # re-assign back
  end

  def images_params
    params.require(:account).permit({images: []}) # allow nested params as array
  end
end

and this is what I get at the console:

Started POST "/store/accounts/1/images/create" for 127.0.0.1 at 2018-03-12 15:21:10 +0200 Processing by ImagesController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"gfqy6KjWtTc3eR2Z9GXJ4/Wx/REzn6mqA+T1q+qGCgXnHkggnsTM4DBPqHKnEmhMPEybL+kTclIoFy1e9+oWiw==", "account"=>{"images"=>[#<ActionDispatch::Http::UploadedFile:0x007ff19f3b75c0 @tempfile=#<Tempfile:/var/folders/hq/pr4rt14n7s31v3f6292wtjm00000gn/T/RackMultipart20180312-3771-jyl4gh.jpg>, @original_filename="image4.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"account[images][]\"; filename=\"image4.jpg\"\r\nContent-Type: image/jpeg\r\n">]}, "id"=>"1"} Account Load (0.2ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]] CACHE Account Load (0.0ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]] (0.2ms) BEGIN Store Load (0.4ms) SELECT "stores".* FROM "stores" WHERE "stores"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]] Account Exists (0.6ms) SELECT 1 AS one FROM "accounts" WHERE "accounts"."business_name" = $1 AND ("accounts"."id" != $2) LIMIT $3 [["business_name", "Example Account"], ["id", 1], ["LIMIT", 1]] Account Exists (0.4ms) SELECT 1 AS one FROM "accounts" WHERE "accounts"."business_description" = $1 AND ("accounts"."id" != $2) LIMIT $3 [["business_description", "There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. "], ["id", 1], ["LIMIT", 1]] Account Exists (0.3ms) SELECT 1 AS one FROM "accounts" WHERE "accounts"."street" = $1 AND ("accounts"."id" != $2) LIMIT $3 [["street", "Stylianou Apostolidi 25"], ["id", 1], ["LIMIT", 1]] SQL (0.6ms) UPDATE "accounts" SET "images" = $1, "updated_at" = $2 WHERE "accounts"."id" = $3 [["images", "{NULL,NULL,image4.jpg}"], ["updated_at", "2018-03-12 13:21:11.408738"], ["id", 1]] (0.4ms) COMMIT

Any ideas how I can make this work?

Upvotes: 0

Views: 329

Answers (1)

Tristin
Tristin

Reputation: 69

I solved the issue of previous images being destroyed 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.blank?
    @images = self[:images]
  end
end  

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

end

Upvotes: 0

Related Questions