Can't add image to existing entry - Strapi v4

Hi,

I can’t figure out what I’m doing wrong. The upload works. The image gets added to the media library and cloudinary. But the data does’t get added to the entry.

Here’s my code:

    const formData = new FormData();
    formData.append('files', image);
    formData.append('ref', 'project');
    formData.append('refId', projectId);
    formData.append('field', 'image');

    const res = await fetch(`${API_URL}/api/upload`, {
      method: 'POST',
      body: formData,
    });
1 Like

same here with python requests:

post_body = {
        "ref": "author",
        "refId": f"{author_id}",
        "field": "picture",
    }
result = requests.post(
        url=f"{api_url}/upload",
        json=post_body,
        files=file_to_upload,
        headers=headers
    )

The image gets uploaded but is not linked with the referred entity

UPDATE: I found that it works if in ref I put api::author.author but I’m not sure if it’s the correct way to do it or is a bug, at least it’s not conforming to the (current) documentation.

So, question for strapi team: it is the documentation that is out of sync or it’s a bug of the software?

same here (i think… i’m new) - but with graphql

mutation testUploadToSpecificEntry($refid:ID, $ref:String, $field:String, $file: Upload!){
  upload(refId: $refid, ref:$ref, field:$field, file:$file){
    data{attributes{name}}
  }
}

variables

{
  "refid": 2,
  "ref": "public/uploads",
  "field":"Pillar_Story_Image"
}

file uploads to media library just fine, but doesn’t update my entry…

this works for me aswell. but it really doesn’t feel like the correct way.

1 Like

It seems that is indeed the new way of doing it: see [v4] Upload files related to entry is not set the field in content type but file uploaded · Issue #11919 · strapi/strapi · GitHub , so it’s the documentation that is out of sync.

Does anyone fix this? I am just trying now and the problem is still there

const fileFormData = new FormData();
fileFormData.append(files, this.cover, this.cover.name);
fileFormData.append(ref, ‘api::event.event’);
fileFormData.append(refId, this.$route.params.id*1); //put the *1 here to try to convert to INT
fileFormData.append(field, ‘cover’);

await this.$http.post(${endpoint}upload, fileFormData,
{
headers: {
‘Authorization’: Bearer ${this.jwt}
}
})

Is weird because I can see on strapi console that actually it is trying to link the image with the reference but the linkage does not work… all works well except the linking

{
method: ‘insert’,
options: {},
timeout: false,
cancelOnTimeout: false,
bindings: [ ‘cover’, 60, ‘27’, ‘api::event.event’ ],
__knexQueryUid: ‘lVZ1cdDPxiF5EnIVqU2-F’,
sql: ‘insert into “files_related_morphs” (“field”, “file_id”, “related_id”, “related_type”) values (?, ?, ?, ?)’,
returning: undefined
}

Same issue here, emillo’s solution did not work for me either. Any help would be appreciated

Anyone having the same issue:

You need to delete/remove the existing image before you can update the field with a new one. Still working on a way to do that :sweat_smile:…I will provide an update if anyone is following along on this thread once I get around to it.

I have the same problem. The solution of Emilio works. But when I delete a record, the linked image is still in the Strapi database.

I was able to create a solution for my desired use being:

User can upload a new profile picture to replace their old one.

Please note I am using the S3 Upload Provider. I know this code may not be super intuitive but it works.

strapi-server.js

plugin.controllers.user.updateProfilePicture = async (ctx) => {
    const user = ctx.state.user;
    

    AWS.config.update({ accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_KEY });


    // User has to be logged in to update themselves
    if (!user) {
      return ctx.unauthorized();
    }

    //Check for existing profile picture
    const userData = await strapi.query('plugin::users-permissions.user').findOne({
      where: { id: user.id },
      populate: { 'profilePicture': true }
    });

    //Get file from request
    const newPic = ctx.request.files.file

    if (userData.profilePicture != null) {
      //Delete existing profile picture
      const s3 = new AWS.S3()
      const params = {
        Bucket: process.env.AWS_BUCKET,
        Key: userData.profilePicture.url.split('/').pop(),
      }
      await s3.deleteObject(params).promise()

      //Delete existing profile picture from entity
      await strapi.query('plugin::users-permissions.user').update({
        where: {id: user.id},
        data:{
          profilePicture: null
        }
      });

      //Call upload function to upload new profile picture
      await strapi.plugin("upload").services.upload.upload({
        data: {
          ref: "plugin::users-permissions.user",
          refId: user.id,
          field: 'profilePicture',
          source: "users-permissions"
        },
        files: {
          path: newPic.path,
          name: newPic.name,
          type: newPic.type,
          size: newPic.size
        }
      })

      return ctx.body = {
        message: "Profile picture updated"
      }

    } else {
      //Call upload function to upload new profile picture
      await strapi.plugin("upload").services.upload.upload({
        data: {
          ref: "plugin::users-permissions.user",
          refId: user.id,
          field: 'profilePicture',
          source: "users-permissions"
        },
        files: {
          path: newPic.path,
          name: newPic.name,
          type: newPic.type,
          size: newPic.size
        }
      })

      return ctx.body = {
        message: "Profile picture updated"
      }
    }
  }

Im sure the same logic can be applied with other upload providers, let me know if you anyone has any questions or suggestions to improve this snippet.

1 Like

make sure you have enable the upload permission and then try the below…

<input type="file" accept="image/*" onChange={(e) => uploadImg(e.target.files[0])} /> 
const formData = new FormData();
  formData.append("files", file);
  formData.append("ref", "api::collection:collection");
  formData.append("refId", "collection's_record_id");
  formData.append("field", "file_field");

  const image = await fetch(`${config.BACKEND_URL}/api/upload`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${session.jwt}`
    },
    body: formData
  });

cheers

Hi, I’m having trouble uploading files through the graph, what should be in the file field?, and you don’t have a repository with the source code?