1

以前,我问过 ActionView::Template::Error (undefined method `image_url')

然后,我解决了错误但没有出现图像,似乎是无法识别照片属性对象或无法在某些库(如 uppy、crooperjs)中获取图像路径,请有人帮帮我

应用程序.js:

//= require popper
//= require bootstrap-sprockets
//= require_tree .

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("jquery")

文件上传.js:

import 'uppy/dist/uppy.min.css'

import cropbox from 'cropbox'

import {
 Core,
 FileInput,
 Informer,
 ProgressBar,
 ThumbnailGenerator,
 Dashboard,
 XHRUpload,
 AwsS3,
 AwsS3Multipart,
} from 'uppy'



 const singleFileUpload = (fileInput) => {
 const imagePreview = document.getElementById(fileInput.dataset.previewElement)
 const formGroup    = fileInput.parentNode

 formGroup.removeChild(fileInput)

 const uppy = fileUpload(fileInput)

  uppy
    .use(FileInput, {
  target: formGroup,
  locale: { strings: { chooseFiles: 'Choose file' } },
})
.use(Informer, {
  target: formGroup,
})
.use(ProgressBar, {
  target: imagePreview.parentNode,
})
.use(ThumbnailGenerator, {
  thumbnailWidth: 600,
})

uppy.on('upload-success', (file, response) => {
    // retrieve uploaded file data
    const uploadedFileData = response.body['data']

    // set hidden field value to the uploaded file data so that it's submitted
    // with the form as the attachment
    hiddenInput.value = JSON.stringify(uploadedFileData)

    cropbox(imagePreview, response.uploadURL, {
      onCrop(detail) {
        let fileData = JSON.parse(hiddenInput.value)
        fileData['metadata']['crop'] = detail
        hiddenInput.value = JSON.stringify(fileData)
      }
    })
   })

 uppy.on('thumbnail:generated', (file, preview) => {
 imagePreview.src = preview
  })
 }

const multipleFileUpload = (fileInput) => {
const formGroup = fileInput.parentNode

const uppy = fileUpload(fileInput)

uppy
 .use(Dashboard, {
   target: formGroup,
   inline: true,
   height: 300,
   replaceTargetContent: true,
 })

uppy.on('upload-success', (file, response) => {
 const hiddenField = document.createElement('input')

  hiddenField.type = 'hidden'
  hiddenField.name = `album[photos_attributes][${randomstring.generate()}][image]`
  hiddenField.value = uploadedFileData(file, response, fileInput)

  document.querySelector('form').appendChild(hiddenField)
  })
  }

  const fileUpload = (fileInput) => {
    const uppy = Core({
    id: fileInput.id,
    autoProceed: true,
    restrictions: {
    allowedFileTypes: fileInput.accept.split(','),
   },
  })

  if (fileInput.dataset.uploadServer == 's3') {
    uppy.use(AwsS3, {
    companionUrl: '/', // will call Shrine's presign endpoint mounted on `/s3/params`
   })
  } else if (fileInput.dataset.uploadServer == 's3_multipart') {
   uppy.use(AwsS3Multipart, {
   companionUrl: '/' // will call uppy-s3_multipart endpoint mounted on `/s3/multipart`
  })
   } else {
    uppy.use(XHRUpload, {
    endpoint: '/upload', // Shrine's upload endpoint
   })
  }

  return uppy
 }

   const uploadedFileData = (file, response, fileInput) => {
   if (fileInput.dataset.uploadServer == 's3') {
   const id = file.meta['key'].match(/^cache\/(.+)/)[1]; // object key without prefix

   return JSON.stringify(fileData(file, id))
  } else if (fileInput.dataset.uploadServer == 's3_multipart') {
  const id = response.uploadURL.match(/\/cache\/([^\?]+)/)[1]; // object key without prefix

  return JSON.stringify(fileData(file, id)) 
  } else {
   return JSON.stringify(response.body)
   }
  }

 // constructs uploaded file data in the format that Shrine expects
 const fileData = (file, id) => ({
    id: id,
    storage: 'cache',
    metadata: {
    size:      file.size,
    filename:  file.name,
    mime_type: file.type,
  }
})

  export { singleFileUpload, multipleFileUpload }

作物箱.js:

import 'cropperjs/dist/cropper.css';

import Cropper from 'cropperjs'

function cropbox(image, url, { onCrop }) {
image.src = url

 new Cropper(image, {
  aspectRatio: 1,
  viewMode: 1,
  guides: false,
  autoCropArea: 1.0,
  background: false,
  zoomable: false,
  crop: event => onCrop(event.detail)
  })
}

export default cropbox

form.html.erb:

<div class="field">
<%  f.label :title %>
<%= f.text_field :title %>
</div>

<div class="field">
<%  f.label :content %>
<%= f.text_area :content %>
</div>

<div class="field ">
<%  f.label :user_id %>
<%= f.hidden_field :user_id, value: current_user.id %>
</div>

<div class ="field form-group">
<%= f.fields_for  :photos, Photo.new do |photos_fileds|  %>

<%= photos_fileds.label :image , class: "form-control" %>
<%= photos_fileds.hidden_field :image,  class: "upload-data", value: 
photos_fileds.object.cached_image_data %>
<%= photos_fileds.file_field  :image , class: "form-control  ", id: "select-files"%><br/>
<div class="image-preview">
<img id="image" src="<%= photos_fileds.object.image_url(:medium) %>" height="300" class="rounded"  >
</div>

<% end %>

</div>



<%= f.submit "create", class: "btn btn-primary" %>
<% end %>

应用程序.scss:

/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= ./bootstrap_import
 *= require_tree .
 *= require_self
 */
 @import "bootstrap";

img {
  display: block;

  /* This rule is very important, please don't ignore this */
  max-width: 100%;
}

.image-preview img {
  display: block;
  max-width: 100%;
}

.image-preview {
 margin-bottom: 10px;
 display: inline-block;
 height: 300px;
}

img[src=""] {
 visibility: hidden;
}
4

0 回答 0