The documentation says about retrieve_from_store!:
Retrieves the file from the storage.
But when I call the method, rather than getting something like a file, I just get an array returned:
irb(main):008:0> uploader.retrieve_from_store!('my_file.png')
=> [:retrieve_versions_from_store!]
What exactly does the method do?
I was looking for the same thing today. Found something from Jonas Nicklas in the CarrierWave forum here...
retrieve_from_store! changes the state of the uploader, it
doesn't return anything sensible. You want to do this:
uploader.retrieve_from_store!('test.jpg')
uploader.do_whatever
The return value from retrieve_from_store! is irrelevant.
I just needed to use model.uploader.read to get to the bytes. It seems, uploader delegates to the file via Proxy: https://github.com/carrierwaveuploader/carrierwave/blob/master/lib/carrierwave/uploader/proxy.rb#L43
Carrierwave is not designed to work without model.
class DocumentUploader < CarrierWave::Uploader::Base
storage :file
def store!(*args)
super
#file
end
def filename
SecureRandom.uuid
end
end
file = uploader.store! file
puts file.path # ok
You can patch retrieve_from_store in the same way.
It will be tricky to retrieve important info for other methods, so please use another uploader if you can.
Related
I am trying to display the filename of a Carrierwave attachment in a Rails erb template. The following does not work:
<%= #page.form.filename %>
This seems in line with the documentation. Is some additional step needed?
My page model looks like this:
class Page < ActiveRecord::Base
mount_uploader :form, FormUploader
end
The form uploader looks like this:
class FormUploader < CarrierWave::Uploader::Base
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_white_list
%w(pdf)
end
end
I have been able to get the filename via the file internal parameter:
<%= #page.form.file.filename %>
The documentation you're looking at is the sanitized file, it's what it uses for actually storing a file. The part you're looking for is FormUploader, which is an Uploader, and part of http://rubydoc.info/gems/carrierwave/0.5.2/CarrierWave/Uploader
If you want to get the file name, you could either read it from the database column directly, or use File.basename(#page.form.path) to extract it easily.
The Carrierwave docs might be a bit off, but recommended way seems to be:
#page.form.file.identifier
#adamonduty's solution is great. Another solution I used before, just create a method on the model:
def name
file.path.split("/").last
end
You're right #epylinkn. Documentation points towards using:
#page.form.file.identifier
But when I use that, I always get nil (just as #Cheng commented).
I then inspected my objects methods (#page.form.file.methods.inspect), and found the following to work:
#page.form.file_identifier
In your model's associated uploader class, define a filename method.
def filename
File.basename(path)
end
You can then call
model_instance.file.filename
Works as of CarrierWave 1.1.0. This is a succinct restatement/amalgamation of kikito and Chris Alley's responses above.
If you're using ActiveRecord, you can directly access the field named form in two ways:
def my_method
self[:form]
end
or
def my_method
form_before_type_cast
end
The second method is read-only.
CarrierWave::SanitizedFile has a private original_filename method containing the filename of the uploaded file. (docs: http://rdoc.info/github/jnicklas/carrierwave/master/CarrierWave/SanitizedFile:original_filename)
After reading through this thread from the CarrierWave mailing list, none seemed to fit my needs. With something like
class Upload < ActiveRecord::Base
mount_uploader :file, FileUploader
# ...
I heavily modify the :file column value from the original filename. Due to this I decided to track the original filename in a separate column from the one bound to CarrierWave. In my FileUploader I simply added a reader that wraps the private original_filename method:
def original_file
original_filename
end
I then added a before_create event to the Upload class (my Upload records are never modified, so a before_create is acceptable for my needs)
before_create do
self.original_file = self.file.original_file
end
I'm assuming you've got models like this?
class Page
mount_uploader :form, FormUploader
end
If so you should be able to call:
#page.form.url
#page.form.filename
Are you sure you've uploaded/attached the file correctly? What do you see when you inspect #page.form? Remember, the attachment will not be saved until you've fully processed the upload.
This is my solution:
before_save :update_file_attributes
def update_file_attributes
if file.present? && file_changed?
self.content_type = file.file.content_type
self.file_size = file.file.size
self.file_name = read_attribute(:file)
end
end
I see by default carrierwave does not delete files linked to model.
How to do it?
Carrierwave should remove the files from S3 automatically for you. I just tested this out on a Rails 3.1 app.
You need to call
#image.destroy
not
#image.delete
Also use refresh button on aws s3 panel
I'm not familiar with carrierwave, but in general, hooking into the after_destroy is likely what you want.
class Model < ActiveRecord::Base
after_destroy :delete_linked_file
def delete_linked_file
# Delete the linked file here
end
end
Yes,
You can do it like this
def delete_image_folder
FileUtils.remove_dir(File.join(Rails.root, File.join( 'public' , file_name.store_dir)), :force => true)
end
but just remember that if you changed the Carrierwave configuration root, you should take it into account (default is public so this code will work)
I think I have a bit of a chicken and egg problem. I would like to set the content_type of a file uploaded via Paperclip. The problem is that the default content_type is only based on extension, but I'd like to base it on another module.
I seem to be able to set the content_type with the before_post_process
class Upload < ActiveRecord::Base
has_attached_file :upload
before_post_process :foo
def foo
logger.debug "Changing content_type"
#This works
self.upload.instance_write(:content_type,"foobar")
# This fails because the file does not actually exist yet
self.upload.instance_write(:content_type,file_type(self.upload.path)
end
# Returns the filetype based on file command (assume it works)
def file_type(path)
return `file -ib '#{path}'`.split(/;/)[0]
end
end
But...I cannot base the content type on the file because Paperclip doesn't write the file until after_create.
And I cannot seem to set the content_type after it has been saved or with the after_create callback (even back in the controller)
So I would like to know if I can somehow get access to the actual file object (assume there are no processors doing anything to the original file) before it is saved, so that I can run the file_type command on that. Or is there a way to modify the content_type after the objects have been created.
Probably you could use upload.to_file. It gives you paperclip temporary file (Paperclip::Tempfile). It has path property, so you can use
self.upload.instance_write(:content_type,file_type(self.upload.to_file.path)
You can get Tempfile using upload.to_file.to_tempfile
Is there a better way to save some string as an attachment via Paperlip as making a tmp file, putting the string into it, opening it again and saving it as an attachment ?
Like this :
def save_string data
tmp_file = "/some/path"
File.open(tmp_file,'w') do |f|
f.write(data)
end
File.open(tmp_file,'r') do |f|
ceneo_xml = f
save!
end
end
There is actually a better way - you can wrap it to StringIO which Paperclip enhances and you will get a pseudo uploaded file in no time. You can customize it by defining instance methods or directly create a subclass of StringIO like this
class InvoiceAttachment < StringIO
def initialize(invoice, content)
#invoice = invoice
super(content)
end
def original_filename
from = #invoice.from
to = #invoice.to
date = #invoice.created_at.strftime('%B-%Y').downcase
"invoice_#{date}_from_#{from}_to_#{to}.pdf"
end
def content_type
'application/pdf'
end
end
Enjoy!
Paperclip stores files alongside your models -- this is what it has been written to do, so I think the short answer is "no".
If you look in attachment.rb in the Paperclip source you'll see a method called def assign uploaded_file. If you look at the implementation of this method you can see that it expects the uploaded file object to have a certain methods defined on it.
You could create your own class which followed the same interface as Paperclip expects, but to be honest your solution of saving a file and assigning that to Paperclip is probably the easiest approach.
I have written this generator code but it returns 'can't convert nil into String' when I call m.directory inside the manifest. Anyone know what had happened?
class AuthGenerator < Rails::Generator::NamedBase
attr_reader :user_class_name
def initialize(runtime_args, runtime_options={})
#user_class_name="User"
#controller_class_name="AccountController"
#user_class_file_name="#{#user_class_name}.rb"
#controller_class_file_name="#{#controller_class_name}.rb"
end
def manifest
record do |m|
m.class_collisions #controller_class_name, #user_class
puts #user_class_name
m.directory File.join('app/models', #user_class_name)
end
end
end
Where is it choking? Please post the full error. You can see the source of the directory method here.
Plus, you probably just want
m.directory File.join('app/models')
Having an app/models/user directory for your generated code is not standard -- unless you're intending namespacing, which it doesn't look like.
Your initialize method needs a call to super.