I want to upload an image to S3 and save to user record with NodeJS, just like the Rails Paperclip gem.
I believe this should be the process, but again I'm quite confused about how this package should work:
- receive an image and resize by paperclip
- save or update to S3
- save file to
user
in DB
I have a Rails Postgres database, and users can upload an image, stored in S3, and reformatted with Paperclip gem. Here's how it is stored:
irb(main):003:0> user.avatar
=> #<Paperclip::Attachment:0x000055b3e043aa50 @name=:avatar,
@name_string="avatar", @instance=#<User id: 1, email:
"[email protected]", created_at: "2016-06-11 22:52:36",
updated_at: "2019-06-16 17:17:16", first_name: "Clarissa",
last_name: "Jones", avatar_file_name: "two_people_talking.gif",
avatar_content_type: "image/gif", avatar_file_size: 373197,
avatar_updated_at: "2019-06-16 17:17:12", @options={:convert_options=>{},
:default_style=>:original, :default_url=>":style/missing.png",
:escape_url=>true, :restricted_characters=>/[&$+,\/:;=?@<>\[\]\
{\}\|\\\^~%# ]/, :filename_cleaner=>nil,
:hash_data=>":class/:attachment/:id/:style/:updated_at",
:hash_digest=>"SHA1", :interpolator=>Paperclip::Interpolations,
:only_process=>[],
:path=>"/:class/:attachment/:id_partition/:style/:filename",
:preserve_files=>false, :processors=>[:thumbnail],
:source_file_options=>{:all=>"-auto-orient"}, :storage=>:s3,
:styles=>{:large=>"500x500#", :medium=>"200x200#",
:thumb=>"100x100#"}, :url=>":s3_path_url",
:url_generator=>Paperclip::UrlGenerator,
:use_default_time_zone=>true, :use_timestamp=>true, :whiny=>true,
:validate_media_type=>true, :adapter_options=>
{:hash_digest=>Digest::MD5},
:check_validity_before_processing=>true, :s3_host_name=>"s3-us-
west-2.amazonaws.com", :s3_protocol=>"https", :s3_credentials=>
{:bucket=>"example", :access_key_id=>"REDACTED",
:secret_access_key=>"REDACTED",
:s3_region=>"us-west-2"}}, @post_processing=true,
@queued_for_delete=[], @queued_for_write={}, @errors={},
@dirty=false, @interpolator=Paperclip::Interpolations,
@url_generator=#<Paperclip::UrlGenerator:0x000055b3e043a8e8
@attachment=#<Paperclip::Attachment:0x000055b3e043aa50 ...>>,
@source_file_options={:all=>"-auto-orient"}, @whiny=true,
@s3_options={}, @s3_permissions={:default=>:"public-read"},
@s3_protocol="https", @s3_metadata={}, @s3_headers={},
@s3_storage_class={:default=>nil},
@s3_server_side_encryption=false, @http_proxy=nil,
@use_accelerate_endpoint=nil>
user.avatar(:thumb)
returns:
https://s3-us-west-2.amazonaws.com/example/users/avatars/000/000/001/thumb/two_people_talking.gif?1560705432
Now, I'm trying to allow the user to upload a new/change image through a react-native app, and the backend is Nodejs, which is relatively new to me.
I'm so confused about how to implement this, especially because the examples are all referencing Mongoose, which I'm not using.
Just to show how I'd successfully update the user, here is how to update first_name
of the user:
users.updateUserPhoto = (req, res) => {
let id = req.decoded.id
let first_name = req.body.first_name
models.Users.update(
first_name: first_name,
{
where: {
id: req.decoded.id
}
},
).then(response => {
res.status(200).json({ status: 200, data: { response } });
})
.catch(error => {
res.status(500).json({ status: 500, err: error });
})
}
Here is the package I found node-paperclip-s3, and here's what I'm trying to do:
'use strict'
let users = {};
const { Users } = require('../models');
let models = require("../models/index");
let Sequelize = require('sequelize');
let Paperclip = require('node-paperclip');
let Op = Sequelize.Op;
let sequelizeDB = require('../modules/Sequelize');
users.updateUserPhoto = (req, res) => {
let id = req.decoded.id
let avatar = req.body.avatar <- this is a file path
models.Users.plugin(Paperclip.plugins, {
avatar: {
styles: [
{ original: true },
{ large: { width: 500, height: 500 } },
{ medium: { width: 200, height: 200 } },
{ thumb: { width: 100, height: 100 } }
],
prefix: '/users/{{attachment}}/{{id}}/{{filename}}',
name_format: '{{style}}.{{extension}}',
storage: 's3',
s3: {
bucket: process.env.S3_BUCKET_NAME,
region: 'us-west-2',
key: process.env.AWS_ACCESS_KEY_ID,
secret: process.env.AWS_SECRET_ACCESS_KEY,
}
}
})
models.Users.update(
avatar,
{
where: {
id: req.decoded.id
}
},
).then(response => {
res.status(200).json({ status: 200, data: { response } });
})
.catch(error => {
res.status(500).json({ status: 500, err: error });
})
}
I've also tried something like this:
models.Users.update(Paperclip.plugins, {
avatar: {
styles: [
{ original: true },
{ large: { width: 500, height: 500 } },
{ medium: { width: 200, height: 200 } },
{ thumb: { width: 100, height: 100 } }
],
prefix: '/users/{{attachment}}/{{id}}/{{filename}}',
name_format: '{{style}}.{{extension}}',
storage: 's3',
s3: {
bucket: process.env.S3_BUCKET_NAME,
region: 'us-west-2',
key: process.env.AWS_ACCESS_KEY_ID,
secret: process.env.AWS_SECRET_ACCESS_KEY,
}
},
{
where: {
id: req.decoded.id
}
},
).then(response => {
res.status(200).json({ status: 200, data: { response } });
})
.catch(error => {
res.status(500).json({ status: 500, err: error });
})
})
I've tried:
let new_avatar = (Paperclip.plugins, {
avatar: {
styles: [
{ original: true },
{ large: { width: 500, height: 500 } },
{ medium: { width: 200, height: 200 } },
{ thumb: { width: 100, height: 100 } }
],
prefix: `/users/avatars/{{attachment}}/{{id}}/{{filename}}`,
name_format: '{{style}}.{{extension}}',
storage: 's3',
s3: {
bucket: process.env.S3_BUCKET_NAME,
region: 'us-west-2',
key: process.env.AWS_ACCESS_KEY_ID,
secret: process.env.AWS_SECRET_ACCESS_KEY,
}
},
})
let data = {
avatar: new_avatar
}
models.Users.update(
data,
{
where: {
id: req.decoded.id
}
},
).then(response => {
res.status(200).json({ status: 200, data: { response } });
})
.catch(error => {
res.status(500).json({ status: 500, err: error });
})
From the example in the link above, I don't understand how it is saving to S3, or how it's updating the database in the same way the Rails gem is creating that record.
Question : how to save resized images + original in the exact same way that the Rails paperclip gem is saving to S3 AND the user
record in the database.
I originally had this open for a 400 point bounty, and am more than happy to still offer 400 points to anyone who can help me solve this. Thanks!!
models.Users.plugin
is undefined? – 鄭脈龍node-paperclip
says "It currently only works with mongoose, but is set up to be easily extended to work with other databases." repo – 鄭脈龍