shrinerb / shrine

File Attachment toolkit for Ruby applications

Home Page:https://shrinerb.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Unpermitted parameter: :images with dropzonejs

dcalixto opened this issue · comments

commented

after setup a simple multiple file upload between item and photos with nested routes

  resources :items, except: [:index] do
resources :photos, only: %i[create destroy]
end

when i try to update the photos item, someone know why this?

Unpermitted parameter: :images. Context: { controller: PhotosController, action: create, request: #<ActionDispatch::Request:0x00007fc6d4ac9688>, params: {"item"=>{"images"=>{"0"=>#<ActionDispatch::Http::UploadedFile:0x00007fc6d4ae4690 @tempfile=#<Tempfile:/tmp/RackMultipart20230824-17259-174kltg.jpg>, @content_type="image/jpeg", @original_filename="caraguatatuba.jpg", @headers="Content-Disposition: form-data; name=\"item[images][0]\"; filename=\"caraguatatuba.jpg\"\r\nContent-Type: image/jpeg\r\n">, "1"=>#<ActionDispatch::Http::UploadedFile:0x00007fc6d4ae4618 @tempfile=#<Tempfile:/tmp/RackMultipart20230824-17259-1u4m5ml.jpg>, @content_type="image/jpeg", @original_filename="background2.jpg", @headers="Content-Disposition: form-data; name=\"item[images][1]\"; filename=\"background2.jpg\"\r\nContent-Type: image/jpeg\r\n">}}, "controller"=>"photos", "action"=>"create", "item_id"=>"130"} }

the dropzone edit form has a file field inside the dropzone fallback container

<div class="fallback">
 <%= f.file_field 'item[images]', multiple: true %>
</div>

and the item and photos controller are using the standard methods

class PhotosController < ApplicationController
  skip_before_action :authenticate_user!, except: %i[create destroy]

  def create
    @item = Item.find(params[:item_id])
    @photo = @item.photos.build(images_params)

    if @photo.save
      redirect_to edit_item_url(@item), notice: 'Photos uploaded successfully'
    else
      render 'items/edit' # Redisplay the form with errors
    end
  end

  def destroy
    @item = Item.find(params[:item_id]) # Make sure you're setting @item correctly
    remove_image_at_index(params[:id].to_i)
    flash[:error] = 'Failed deleting image' unless @item.save
    redirect_back(fallback_location: item_path(@item))
  end

  private

  def find_item
    @item = Item.find(params[:item_id])
  end

  def photo_params
    params.require(:photo).permit(:image)
  end

  def remove_image_at_index(index)
    remain_images = @item.photos.to_a # copy the array
    deleted_image = remain_images.delete_at(index) # delete the target image
    deleted_image.try(:destroy!) # delete image from S3
    @item.photos = remain_images # re-assign back

    @item.photos.remove_images = true if remain_images.length.zero?
  end

  def images_params
    params.require(:item).permit(images: [])
    # look into format which comes, may be here will be image: {...}
    # allow nested params as array
  end
end
class ItemsController < ApplicationController

  def edit
  @item = Item.friendly.find(params[:id])
    @photos = @item.photos
  end


  def update

    if @item.update(item_params)
      @item.published_at = Time.now



      if params[:item][:images]
        params[:item][:images].each do |image|
          Photo.create(item: @item, image: image)
        end
      end
end
      redirect_to item_url(@item), notice: 'O item foi atualizado'
 
    else
      render :edit, status: :unprocessable_entity

    end
  end

the dropzone

$(function(){
    var post_url = "/items/<%= @item.id %>/photos";
    var myDropzone = new Dropzone("#myDropzone", {
      url: post_url,
           //url: "/photos",
      method: "POST",
      paramName: "item[images]",
      uploadMultiple: true,
      autoProcessQueue: true,
      addRemoveLinks: true,
      parallelUploads: 6,
      maxFiles: 6,
      
      removedfile: function(file){
        var _ref,
            item_id = file.item_id,
            image_index = file.index,
            url = "/items/" + item_id + "/photos/" + image_index;
        $.ajax({
            type: 'DELETE',
            url: url
        });
        return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
      },
      headers: {
      'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')},
      init: function() {
        var myDropzone = this;
        $("input[type='submit']").on("click", function(e) {
            if (myDropzone.getQueuedFiles().length > 0) {
                e.preventDefault();
                e.stopPropagation();
                myDropzone.processQueue();
                return;
            }
        });
        this.on("successmultiple", function(files, response) {
          window.location.href = '<%= edit_item_url(@item) %>'
        });
      }
    });



   <% @photos.each_with_index do |image, index| %>
      var mockFile = {
        name: "<%= image.image.id %>",
          size: "<%= image.image.size%>",
        index: <%= index %>,
        item_id : <%= @item.id %>
      }
      myDropzone.files.push(mockFile);
      myDropzone.emit("addedfile", mockFile);
      myDropzone.options.thumbnail.call(myDropzone, mockFile,"<%= image.image_url(:medium) %>");
     // myDropzone.createThumbnailFromUrl(mockFile, "<#%= image.url %>");
      myDropzone.emit("complete", mockFile);

    <% end %>




  });

Very hard to debug this.

Try the following:

def images_params
    params.require(:item).permit(images: {})   # <---- notice the curly bracked
end

https://apidock.com/rails/ActiveRecord/NestedAttributes/ClassMethods/accepts_nested_attributes_for
class Photo < ActiveRecord
   has_many :images  # is this what you are trying for?
   accepts_nested_attributes_for :images # not sure if this is what you want.
end
commented

@benkoshy thank you but the item has many photos!
and the photo has image attachment

class Photo < ApplicationRecord
  include ImageUploader::Attachment(:image)
  belongs_to :item
  validates :image, presence: true

end

and item

class Item < ApplicationRecord

has_many :photos, dependent: :destroy

  accepts_nested_attributes_for :photos, allow_destroy: true, reject_if: proc { |attributes|
                                                                           attributes['image'].blank? && attributes['id'].blank?
                                                                         }
  end

It is very hard to debug like this: but I would prefer something along the following linkes:

def item_params
    params.require(:item).permit(photo_attributes: {}) # use the hash                                               
end

It looks like you forgot to permit some parameters. This is not a bug in Shrine, because Shrine doesn't permit parameters for you.