Paperclip: How to store a picture in a Rails console? - ruby-on-rails

I tried storing a local image in a rails console.
Because I have many pictures in my local storage (I use crawler to download tons of pictures), I want to store them into a database, with the benefit of paperclip to do some image job, like thumbnail etc.
If I use a webpage to save new pictures to database one by one, it will cost a lot of time. So I want to find a way in rails console (some code) that can batch save-picture-into-database.

To further clarify #andrea's answer:
YourPaperclippedModelHere.new(:your_paperclip_field => File.new(path, "r"))
So if your model is called Image and your paperclip field is data:
Image.new(:data => File.new(path_to_your_file, "r"))

If this is the model:
class User < ActiveRecord::Base
has_attached_file :avatar
end
then the following should work from the console:
>> User.create(:avatar => File.open('/path/to/image.jpg', 'rb'))

I dont know if it is what you want ... but
to save an paperclip asset from console
You could simple use a File instance .
a.e.
Image.new :data=>File.new("/path/to/image.jpg","r")

Late Answer but hopefully it will work for others.
You need to include.
File.new("#{Rails.root}/public/images/default_avatar.png", "r")

Related

Seeding multiple image attachments from Amazon S3 in Rails

I am trying to seed multiple image attachments to a model. I have been using this link but I am still sort of stuck since what I aim to do differs a little since:
I am trying to attach multiple images to each object (which I seed) in the model
I want to retrieve these images from my S3 bucket and attach them to the objects (is this possible?)
Here's my seed.rb:
shirt = Item.create(name:"Basic Shirt",price:19.99)
skirt = Item.create(name:"Basic Skirt",price:29.99)
sweater = Item.create(name:"Basic Sweater",price:39.99)
kid_hood = Item.create(name:"Basic Kid Hoodie",price:19.99)
# somehow attach images here?
I am using the aws-sdk-s3 gem in order to connect Active Storage to my S3 bucket. Please tell me if any additional files are needed for viewing. I will happily edit this post to include it.
ActiveStorage work on plain byte streams, so you can download the file (using open-uri for instance) and assign the stream as the content of the attachment.
Assuming you have the following (adapt if different)
class Item < ApplicationRecord
has_one_attached :photo
end
you can have your seeds as:
require 'open-uri'
shirt = Item.create(name:"Basic Shirt",price:19.99)
shirt.photo.attach(io: open('your-s3-nonexpiring-url'), filename: 'foo.bar')
# ...
Just a note: as of Ruby 3.0, you will need to call URI.open instead of open. See the reference to open-uri here.

Saving image created with RMagick using Rails and CarrierWave

In my Rails app I have a module that takes several images, and using RMagick "stitches" them together into a new single image. I'm able to successfully create the final image, but I'm having trouble saving this new image as an attachment to a model (using CarrierWave). The method that does the stitching looks like this:
def generate_collage(params)
final_image = ImageList.new
# ... code that puts together the composite image ...
return final_image.append(true).to_blob { |attrs| attrs.format = 'JPEG' }
end
I've got my User model with an uploader mounted:
class User < ActiveRecord::Base
mount_uploader :image, UserImageUploader
end
In the CarrierWave documentation under the ActiveRecord section, they show how to assign a new image, but they assume the file already exists somewhere. In my case it doesn't yet exist on the filesystem, and I'm outputting a blob... is there any way to go from that blob to generating an image upload for CarrierWave?
I suppose I'm trying to avoid saving this image temporarily into "#{Rails.root}/tmp/" and then reading it from there... it seems like I could cut out this step and send directly to CarrierWave somehow, but I don't know how! Is it possible?
I'm working on something similar right now. This should be possible, but an easy workaround is to save it to a temp file:
temp_file = Tempfile.new([ 'temp', '.png' ])
image.write(temp_file.path)
user = User.new
user.avatar = temp_file
user.save
temp_file.close
temp_file.unlink
I'm hoping to try to improve it to remove the file system dependency completely, by following the advice in one of these answers: How to handle a file_as_string (generated by Prawn) so that it is accepted by Carrierwave?

Rails - Run an external program on a Paperclip attachment for processing and save the output attachment back to the model

In my rails project, I need the user to upload a file (input_file) which I will process using an external application. Once, it is completed, I want to attach the processed file to the same model as a different attachment (output file).
I have been able to create a form and use paperclip to allow the user to upload the input_file to my model FileProcessor. Im not sure on the next step as to how do I call an executable on the input_file and save it as output_file.
Based on paperclip, once the file is upload, I can access the path via input_file.path
output_file = %w{external_app input_file.path out_file_name}
Class FileProcessor
has_attached_file :input_file
has_attached_file :output_file
Im confused as to where this call to run the external app be placed? in the model or in the controller (def create). Also, how do I work with paperclip to associate the output_file with the model without actually uploading.
The location for such code depends on what kind of business your external process does. With the requirements as depicted in the question, it would be as simple as this:
class FileProcessor < ActiveRecord
...
after_validation do |fp|
tmp_file = "/tmp/#{rand}"
system "/usr/bin/awesome.sh #{fp.input_file.path} > #{tmp_file}"
fp.output_file = File.open(tmp_file)
end
...
end
I hope, this is what you are looking for.

How do you access the raw content of a file uploaded with Paperclip / Ruby on Rails?

I'm using Paperclip / S3 for file uploading. I upload text-like files (not .txt, but they are essentially a .txt). In a show controller, I want to be able to get the contents of the uploaded file, but don't see contents as one of its attributes. What can I do here?
attachment_file_name: "test.md", attachment_content_type: "application/octet-stream", attachment_file_size: 58, attachment_updated_at: "2011-06-22 01:01:40"
PS - Seems like all the Paperclip tutorials are about images, not text files.
In Paperclip 3.0.1 you could just use the io_adapter which doesn't require writing an extra file to (and removing from) the local file system.
Paperclip.io_adapters.for(attachment.file).read
#jon-m answer needs to be updated to reflect the latest changes to paperclip, in order for this to work needs to change to something like:
class Document
has_attached_file :revision
def revision_contents(path = 'tmp/tmp.any')
revision.copy_to_local_file :original, path
File.open(path).read
end
end
A bit convoluted as #jwadsack mentioned using Paperclip.io_adapters.for method accomplishes the same and seems like a better, cleaner way to do this IMHO.
To access the file you can use the path method:
csv_file.path
http://rdoc.info/gems/paperclip/Paperclip/Attachment#path-instance_method
This can be used along with for example the CSV reader.
Here's how I access the raw contents of my attachment:
class Document
has_attached_file :revision
def revision_contents
revision.copy_to_local_file.read
end
end
Please note, I've omitted my paperclip configuration options and any sort of error handling.
You would need to load the contents of the file (using Rubys File.open) into a variable before you show it. This may be an expensive operation if your app gets lots of use, so it may be worthwhile reading the contents of the file and putting it into a text column in your database after uploading it.
Attachment already inherits from IOStream. http://rdoc.info/github/thoughtbot/paperclip/master/Paperclip/Attachment
So it should just be "#{attachment}" or <% RDiscount.new(attachment).to_html %> or send_data(attachment). However you wanted to display the data.
This is a method I used for upload from paperclip to active storage and should provide some guidance on temporarily working with a file in memory. Note: This should only be used for relatively small files.
Written for gem paperclip 6.1.0
Where I have a simple model
class Post
has_attached_file :image
end
Working with a temp file in ruby so we do not have to worry about closing the file
Tempfile.create do |tmp_file|
post.image.copy_to_local_file(nil, tmp_file.path)
post.image_temp.attach(
io: tmp_file,
filename: post.image_file_name,
content_type: post.image_content_type
)
end

Preventing Paperclip from deleting/overwriting attachments on update

I'm having a hard time figuring out how to prevent Paperclip from deleting the old version of an attachment (image).
I have a model, Site, which has an attachment, logo. I would like to keep the old logos around since I will be keeping track of changes to the model and would like to view the history of logos.
I'm keeping track of the changes in another model, which has a reference to file paths. My problem is that when updating a site with a new logo, Paperclip will flush the old logo first.
It surprises me that there's not an option you can switch to prevent Paperclip from flushing the old attachment before creating the new one.
Any ideas?
There's a new option that tells paperclip to preserve old attachments:
https://github.com/thoughtbot/paperclip/commit/65e8d4f6de50732d8e1b
https://github.com/thoughtbot/paperclip/issues/60
Simple to use:
has_attached_file => :attachment,
:styles => { :thumb => 100x100! },
:preserve_files => true
It's not documented yet and took some digging to find so I wanted to share it here.
Because attachments are defined at the class level, Paperclip interpolates the symbols in your strings using it's own interpolation library. You can create your own interpolations using this library.
I would add a field to the model called attachment_version or something similar, and then increment this version number each time the file is changed. Then, create an interpolation for it in an initializer file:
Paperclip.interpolates :version do |attachment, style|
attachment.instance.attachment_version
end
Now you can use :version in your strings:
class Model < ActiveRecord::Base
has_attached_file :something, :path => " :rails_root/public/somethings/etc/:version.:extension"
end
See the wiki documentation for more information.
[Update]
After some digging around (see the comments to this answer), I've come to the conclusion that Paperclip will still delete the old attachment due to code that's called in Paperclip::Atachment#attach. Probably the best way to deal with this is to create a new storage engine based on Paperclip::Storage::Filesystem and overwrite #flush_deletes. Note that there is no way in that method to tell if a file is being queued for deletion because of the model it belongs to being deleted or a new file is being uploaded in its place.
lib/paperclip_monkey_patch.rb:
module Paperclip
class Attachment
def clear
# nop
#raise "hell"
# op
instance_write(:file_name, nil)
instance_write(:content_type, nil)
instance_write(:file_size, nil)
instance_write(:updated_at, nil)
end
end
end
Then add this line at the top of any file that deleted attachments:
require 'paperclip_monkey_patch'
Thanks to Ruby Forum
I had a similar issue with Paperclip attachments at when working on a Rails blog last summer.
There is a patch that addresses this. I wasn't able to get it working for myself, but it's worth a shot!
http://github.com/alainravet/paperclip/tree/keep_old_files

Resources