ruby-on-railsruby-on-rails-5shrine

How do you seed images using Shrine


I can't seed my images using shrine, unlike carrierwave the below code doesn't work.

Profile.create! id: 2,
                user_id: 2, 
                brand: "The Revengers", 
                location: "Azgaurd", 
                phone_number: "send a raven",
                image_data: File.open(Rails.root+"app/assets/images/seed/thor.png")

i've also tried

image_data: ImageUploader.new(:store).upload(File.open(Rails.root+"app/assets/images/seed/thor.png"))

but it returns

JSON::ParserError in Profiles#show
743: unexpected token at '#<ImageUploader::UploadedFile:0x007fd8bc3142e0>'

Is there a shrine way? I can't seem to find it anywhere.

shrine.rb

require "cloudinary"
require "shrine/storage/cloudinary"


Cloudinary.config(
  cloud_name: ENV['CLOUD_NAME'],
  api_key:ENV['API_KEY'],
  api_secret:ENV['API_SECRET'],
)

Shrine.storages = {
  cache: Shrine::Storage::Cloudinary.new(prefix: "cache"), # for direct 
uploads
  store: Shrine::Storage::Cloudinary.new(prefix: "store"),
}

profile.rb

class Profile < ApplicationRecord
  include ImageUploader[:image]
  belongs_to :user
  has_and_belongs_to_many :genres
  scoped_search on: [:brand]
end

image_uploader.rb

class ImageUploader < Shrine
end

Solution

  • Using Shrine, the attachment attribute (e.g. image_data) on the model (e.g. Profile) is a text column in the database (you can define it as json or jsonb too). Now it should be clear that this column cannot accept a File object (which you are trying to do).

    First you need to use an uploader (e.g. ImageUploader) to upload the target file in one of your configured Shrine storages (e.g. :cache or :store):

    uploader = ImageUploader.new(:store)
    file = File.new(Rails.root.join('app/assets/images/seed/thor.png'))
    uploaded_file = uploader.upload(file)
    

    Here the main method of the uploader is #upload, which takes an IO-like object on the input, and returns a representation of the uploaded file (ImageUploader::UploadedFile) on the output.

    At this point, you have the uploaded file in hand. Now the model (Profile) will only need the json representation of the uploaded file in its attachment attribute column (image_data) like so:

    Profile.create! id: 2,
                    user_id: 2, 
                    brand: "The Revengers", 
                    location: "Azgaurd", 
                    phone_number: "send a raven",
                    image_data: uploaded_file.to_json