6

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
Wasif Hossain
  • 3,900
  • 1
  • 18
  • 20
Ric-lavers
  • 73
  • 7

2 Answers2

13

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
Wasif Hossain
  • 3,900
  • 1
  • 18
  • 20
0

Updating this answer to work with the latest version of Shrine (3.4.0).

models/profile.rb

class Profile < ApplicationRecord
  #  image_data  :jsonb (in the database)

  # add an `image` virtual attribute managed by Shrine
  include ImageUploader::Attachment.new(:image)
end

In a rails console:

file = URI.open("https://picsum.photos/200/300")
profile = Profile.first
profile.image = file
profile.save

With that, the uploader uploads and processes the file as if it were uploaded in a form.

Troy
  • 5,319
  • 1
  • 35
  • 41