I have a directory of existing files which I need to migrate into my rails app as part of a legacy migration. Essentially I need to upload these files manually and save a new record for them in the database. I haven't quite found the proper way to do this. Currently I have the following in a rake task:
#attachments.each do |attachment|
begin
new_attachment = Attachment.new
#attachment_file_path = "/home/username/Attachments/" + attachment.Filename
file = File.open(#attachment_file_path)
new_attachment[:file] = new_attachment.file.store!(file)
# Map old record fields to new
new_attachment.attributes = {
:project_id => attachment.ProjectID,
:name => attachment.Description,
:user_id => attachment.UserId,
:created_at => attachment.CreatedDate,
:updated_at => attachment.LastModifiedDate
}
new_attachment.save!
puts "Attachment added successfully "
rescue => error
puts "Error migrating Attachment: #{error}"
end
end
attachment.rb
class Attachment < ActiveRecord::Base
mount_uploader :file, FileUploader
end
uploader:
class FileUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
include CarrierWave::MimeTypes
process :set_content_type
storage :fog
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_white_list
%w(jpg jpeg gif png pdf doc docx txt)
end
version :thumb do
process resize_to_fit: [152, nil]
end
def default_url
ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
end
protected
def image?(new_file)
if new_file.content_type == nil
return false
else
new_file.content_type.include? 'image'
end
end
end
This does not work currently. The file never gets uploaded, and occasionally I get the following error:
Failed to manipulate with rmagick, maybe it is not an image? Original Error: no decode delegate for this image format
In this instance, the file is a '.doc' file.
What is the correct way to open a local file and upload it manually via Carrierwave?
Any help is appreciated.
Try this
#attachments.each do |attachment|
begin
options = {
:project_id => attachment.ProjectID,
:name => attachment.Description,
:user_id => attachment.UserId,
:created_at => attachment.CreatedDate,
:updated_at => attachment.LastModifiedDate,
:file => File.new(File.join("/home/username/Attachments/",attachment.Filename))
}
new_attachment = Attachment.new(options)
new_attachment.save!
puts "Attachment added successfully "
rescue => error
puts "Error migrating Attachment: #{error}"
end
end
Perhaps that would do for you as carrierwave would internally call store! for you
Question?
Failed to manipulate with rmagick, maybe it is not an image? Original Error: no decode delegate for this image format
Not sure what are you trying to over here because you have define an image? method which is not specified in condition also is that something that you want the content_type to be only present for image file
if no perhaps only the process call would work
process :set_content_type
if yes then perhaps you have to do something like this
process :set_content_type , :if => :image?
def image?(new_file)
%w(jpg jpeg gif).include?(new_file.extension)
end
Hope this help
EDIT based upon the comment
try this just used the condition same logic
version :thumb ,:if => image? do
// your code
end
Related
On development, it's correctly creating a resized version of original image and storing both of them, but on s3, it's just uploading 2 identical versions without any kind of modification (apart from renaming it). There are no exceptions shown anywhere. Any idea where the problem might be?
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS',
:aws_access_key_id => 'a',
:aws_secret_access_key => 'a',
:region => "us-west-1"
}
config.fog_directory = 'a'
end
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
def store_dir
"images/#{model.id}"
end
version :normalized do
process :resize_to_limit => [450,450]
end
def extension_white_list
%w(jpg jpeg gif png)
end
if Sinatra::Base.development?
storage :file
else
storage :fog
end
end
Although there were no errors, running "convert -version" on production machine revealed that imagemagick was not installed. Installation fixed the issue.
I have a Redmine plugin. I create a temporary file in /tmp, then I send it with File.open. I want to delete the temporary file when user has download it. How can I do ?
My code (in a controller):
File.open(filelocation, 'r') do |file|
send_file file, :filename => filename, :type => "application/pdf", :disposition => "attachment"
end
If I remove the file after File.open, it doesn't work.
EDIT
In my controller I do:
def something
temp = Tempfile.new(['PDF_','.pdf'])
# ... some code that modify my pdf ...
begin
File.open(temp.path, 'r') do |file|
send_file file, :filename => temp.path, :type => "application/pdf", :disposition => "attachment"
end
ensure
temp.close
temp.unlink
end
end
My temporary file is remove, but not in the end of my code: the File.open return a damage PDF.
I use send_data instead of send_file, then I delete the file. send_data will block until the data is sent, allowing File.delete request to succeed.
file = temp.path
File.open(file, 'r') do |f|
send_data f.read.force_encoding('BINARY'), :filename => filename, :type => "application/pdf", :disposition => "attachment"
end
File.delete(file)
source: In Ruby on Rails, After send_file method delete the file from server
Call send_file can be offloaded to a web server, therefore it can return asynchronously. Doing anything in tempfile block is dangerous as well as trying to close and unlink the file. When using send_file, the only option is to give up on cleaning the temporary files within the web process.
Consider using the Tempfile class for your job:
Tempfile.create('foo', '/tmp') do |f|
... do something with f ...
end
It's included in standard library and cleanup occur automatically when the block is closed.
Reference:
http://www.ruby-doc.org/stdlib-2.1.1/libdoc/tempfile/rdoc/index.html
In my rails app I'm trying to add tags to images uploaded to cloudinary cloud.
in my carrierwave, ImageUploader class
include Cloudinary::CarrierWave
# def cache_dir
# "#{Rails.root}/tmp/uploads"
# end
#
process :convert => 'jpg'
cloudinary_transformation :quality => 80
process :tags => [ 'tag', model.name]
...
I'm trying to add name of the record in tags, but it gives error
method 'model' is undefined for class ImageUploader.
how can I access value of the field name inside my uploader.
I'm new to rails.
please help, thanks in advance!
You can use the following:
class PictureUploader < CarrierWave::Uploader::Base
include Cloudinary::CarrierWave
process :convert => 'jpg'
cloudinary_transformation
:quality => 80
process :assign_tags
def assign_tags
return :tags => ['tag', model.name]
end
end
You can define any method that returns a hash of parameters. Then you can apply the custom method using the 'process' call. The parameters are passed to the upload API call.
I am migrating from Paperclip to Carrierwave. Here I am trying to convert the processing commands for thumbnail generations:
has_attached_file :image,
styles: {
thumb: '220x140#',
big: '620x600>',
no_proportion: '255x162!'
},
convert_options: {
all: '-strip',
thumb: '-delete 1--1',
no_proportion: '-delete 1--1'
}
I am planning to use MiniMagick. I got that I convert from 220x140# to resize_to_fill(220,140), but I am not sure how to convert all the other commands.
P.S. It would be better if I can reuse the existing ImageMagick commands and parameters, even for resizing (i.e. not using built-in helper resizer).
I have done the following. However I am not sure if it is totally equivalent.
process :strip
# Create different versions of your uploaded files:
version :thumb do
process :resize_to_fill => [220,140]
end
version :mobile do
process :resize_to_fill => [320,210]
end
version :mobile_small do
process :resize_to_fill => [256,168]
end
version :big do
process :resize_to_limit => [620,600]
end
version :groupbuy_ad do
process :resize_to_fill => [96,60]
end
version :email do
process :resize_to_fill => [125,125]
end
version :widget_165 do
process :resize_to_fill => [165,105]
end
version :widget_100 do
process :resize_to_fill => [100,64]
end
version :no_proportion do
process :resize => '255x162!'
end
def strip
manipulate! do |img|
img.strip
img = yield(img) if block_given?
img
end
end
def resize(dimension)
manipulate! do |img|
img.resize dimension
img = yield(img) if block_given?
img
end
end
def get_first_frame
manipulate! do |img|
img = img.delete '1--1'
end
end
What I have is a Theme model, which contains many Assets. Assets are using Paperclip and storing their file content in my Amazon AWS-S3 system. I'm also using deep_clone because my customers have the ability to copy built in Themes and then modify them to their hearts content. All the deep_clone stuff is working great, but when I deep_clone the assets, the old file contents don't get added to my S3 buckets. The record gets saved to the database, but since the file-contents don't get saved with the new ID the file.url property points to a dead file.
I've tried calling paperclip's save and create method manually but I can't figure out how to get paperclip to "push" the file back to the bucket since it now has a new ID, etc....
require 'open-uri'
class Asset < ActiveRecord::Base
belongs_to :theme
attr_accessor :old_id
has_attached_file :file,
:storage => "s3",
:s3_credentials => YAML.load_file("#{RAILS_ROOT}/config/aws.yml")[RAILS_ENV],
:bucket => "flavorpulse-" + RAILS_ENV,
:path => ":class/:id/:style.:extension"
validates_attachment_presence :file
validates_attachment_size :file, :less_than => 5.megabytes
before_save :delete_assets_in_same_theme_with_same_name
after_create :copy_from_cloned_asset
private
def delete_assets_in_same_theme_with_same_name
Asset.destroy_all({:theme_id => self.theme_id, :file_file_name => self.file_file_name})
end
def copy_from_cloned_asset
if (!old_id.blank?)
if (old_id > 0)
old_asset = Asset.find(old_id)
if (!old_asset.blank?)
self.file = do_download_remote_image(old_asset.file.url)
self.file.save
end
end
end
end
def do_download_remote_image (image_url)
io = open(URI.parse(image_url))
def io.original_filename; base_uri.path.split('/').last; end
io.original_filename.blank? ? nil : io
rescue # catch url errors with validations instead of exceptions (Errno::ENOENT, OpenURI::HTTPError, etc...)
end
end
Any ideas on how I can get paperclip to push the file? I also wouldn't be opposed to doing this using Amazon's aws-s3 gem but I couldn't seem to get that to work either.
According to this former question/answer, it should be possible with this simple line of code:
self.file = old_asset.file