Created
June 30, 2021 22:12
Star
You must be signed in to star a gist
File Upload using Rails ActiveStorage, GraphQL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Mutations::UploadAvatar < Mutations::BaseMutation | |
null true | |
field :success, Boolean, null: false | |
field :errors, [String], null: true | |
field :thing, Types::ThingType, null: true | |
# query: | |
# mutation requestResetPassword($input: UploadAvatarInput!) { | |
# uploadAvatar(input:$input) { | |
# success | |
# errors | |
# user { avatar_url } | |
# } | |
# } | |
# | |
# variables: | |
# { | |
# "input": { | |
# "id": "1", | |
# "avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAANlBMVEVmZmb///9mZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZW6fJrAAAAEXRSTlMAAAYHG21ub8fLz9DR8/T4+RrZ9owAAAB3SURBVHja7dNLDoAgDATQWv4gKve/rEajJOJiWLgg6WzpSyB0aHqHiNj6nL1lovb4C+hYzkSNAT7mryQFAVOeGAj4CjwEtgrWXpD/uZKtwEJApXt+Vn0flzRhgNiFZQkOXY0aADQZCOCPlsZJ46Rx0jhp3IiN2wGDHhxtldrlwQAAAABJRU5ErkJggg==" | |
# } | |
# } | |
def resolve(attributes:) | |
user = User.find_by(id: attributes[:id]) | |
# attributes[:avatar] is passed in as a base64 string | |
Tempfile.open('avatar') do |file| | |
file.write Base64.decode64(attributes[:file].split(",")[1..-1].join) | |
user.avatar.attach( | |
io: file, | |
filename: 'avatar', | |
) | |
end | |
return { | |
success: true, | |
errors: [], | |
user: user | |
} | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Types | |
class UserType < Types::BaseObject | |
field :avatar_url, String, null: true | |
def avatar_url | |
Rails.application.routes.url_helpers.rails_blob_url(object.avatar) | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class User < ApplicationRecord | |
has_attached_file :avatar | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import toBase64 from 'toBase64'; | |
const ImageUpload = ({ id, field, form, disabled, user }) => { | |
const [preview, setPreview] = useState(user.avatarUrl); | |
return ( | |
<div className="w-100 d-flex justify-content-center"> | |
<label | |
htmlFor="avatar" | |
style={{ position: 'relative' }} | |
className="avatar avatar-xxl mb-4 mx-auto" | |
style={{ position: 'relative', cursor: 'pointer' }}> | |
{preview && preview !== '/images/user-icon.png' ? ( | |
<img | |
src={preview} | |
className="avatar-img rounded-circle" | |
style={{ | |
backgroundColor: getDefaultAvatarColors( | |
`${user.firstName} ${user.lastName}`, | |
), | |
}} | |
/> | |
) : ( | |
<div | |
className="avatar-img rounded-circle d-flex align-items-center text-center" | |
style={{ | |
backgroundColor: getDefaultAvatarColors( | |
`${user.firstName} ${user.lastName}`, | |
), | |
}} | |
/> | |
)} | |
<i | |
className="fe fe-camera" | |
style={{ | |
fontSize: '32px', | |
width: '32px', | |
height: '32px', | |
position: 'absolute', | |
left: 0, | |
right: 0, | |
bottom: 0, | |
top: 0, | |
margin: 'auto', | |
color: '#BFBFC1', | |
lineHeight: 1, | |
}} | |
/> | |
</label> | |
<input | |
style={{ display: 'none' }} | |
type="file" | |
name={field.name} | |
disabled={disabled} | |
id="avatar" | |
onChange={e => { | |
const file = e.currentTarget.files[0]; | |
form.setFieldValue(field.name, file); | |
toBase64(file).then(base64 => { | |
setPreview(base64); | |
}); | |
}} | |
/> | |
</div> | |
); | |
}; | |
// then use `preview` in state to upload via apollo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const toBase64 = file => | |
new Promise((resolve, reject) => { | |
const reader = new FileReader(); | |
reader.readAsDataURL(file); | |
reader.onload = () => resolve(reader.result); | |
reader.onerror = error => reject(error); | |
}); | |
export default toBase64; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment