I'm trying to send messages with attachments, using CarrierWave.
In Mailboxer gem I find that the uploader mounted here.
It uses AttachmentUploader for the field :attachment
In base functionality all works good. Attached files stored in public/uploads folder.
But I need add custom functionality to AttachmentUploader (Eg. change the path to store attachments etc.).
I trying create my own attachment_uploader.rb in app/uploaders but it doesn't work.
I just added to initializers/mailboxer.rb
...
class AttachmentUploader < AllAttachmentUploader
end
It allow me inherit from AllAttachmentUploader to AttachmentUploader which was defined in Mailboxer.
Related
I am using rails_admin gem for the rails api application for the backend admin side.
I am using rails 6 with active_storage and storing attachments on the S3.
On the admin side, I need to display the list of attachments which might be images or files anything.
My question is How to show those in index method, do I need to show images then what to show in pdf/docs, do I need to show the only the link of s3?
currently, it looks like these broken images are the images and other one were files
My model
class Attachment < AttachmentBlock::ApplicationRecord
self.table_name = :attachments
include Wisper::Publisher
has_one_attached :attachment
belongs_to :account, class_name: 'AccountBlock::Account'
has_and_belongs_to_many :orders , class_name: 'BxBlockOrdermanagement::Order'
scope :not_expired, -> {where('is_expired = ?',false)}
end
What should I use here to list the attachment that the user upload?
how to check the attachment type and then if its image then shows the image and if it files then show file url from s3?
thanks.
Yours is a two part question:
To add links to the side menu on rails admin you need to define models so if you wanted an index for all the attachments of type 'pdf' you could use rails STI (single table inheritance) or define a custom default_scope like this:
class ImageAttachment < Attachment
def self.default_scope
where('attachments.attachment LIKE ?', '%png') }
end
end
To customize the row of each individual attachment record you need to defined that behavior for the field on the model rails admin config.
For example you can put this block of code inside your ImageAttachment class.
class ImageAttachment < Attachment
def self.default_scope
where('attachments.attachment LIKE ?', '%png') }
end
rails_admin do
configure :attachment do
view = bindings[:view]
attachment = bindings[:object]
if view
view.content_tag(:img, attachment.attachment.url)
else
''
end
end
list do
field :attachment
end
end
end
As you can see inside the attachment field configuration block you have access to the attachment object and of course all its methods, you can determine the type of attachment and do some special html rendering.
I'm using the possibility to upload multiple files at once with carrierwave as described here:
https://github.com/carrierwaveuploader/carrierwave#multiple-file-uploads
So I have
class Item < ActiveRecord::Base
mount_uploaders :images, ImagesUploader
serialize :images, JSON
...
end
Now I want to upload a remote file (not from local drive). Usually I would use something like this in my controller
class ItemsController < ApplicationController
...
item.remote_images_url = params[:image_url]
...
end
But the helper remote_images_url (mind the plural version remote_images_url) only give me
undefined method remote_images_url
I also tried remote_image_url which would be the default helper in case of single file upload. Also undefined method.
How can I upload remote files when using "multiple files upload" with carrierwave?
Eventually I had a look into the github repository of carrierwave and I found this:
https://github.com/carrierwaveuploader/carrierwave/blob/master/lib/carrierwave/mount.rb
Luckily it's all described in the comments in this file. There was only one little thing I had to change. In the comments it says that for a column called images I had to use the helper method remote_image_urls. But actually I have to use remote_images_urls (always plural).
So that's the solution in my case:
class Item < ActiveRecord::Base
mount_uploaders :images, ImagesUploader
serialize :images, JSON
...
end
class ItemsController < ApplicationController
...
item.remote_images_urls = [params[:image_url]]
...
end
Mind the right plural types in the helper method as well as the surrounding array for the params (carrierwave excpects an array).
You need to use item.remote_images_urls not item.remote_images_url and assign the array of remote url. This works for me although CarrierWave rubydoc suggests me to use item.remote_image_urls . So, maybe you should try one of these .
For reference CarrierWave rubydoc
I'm trying to rename a model and the corresponding tables, it worked out fine. What about the upload folder? Used something like this that tied the uploader folder to the model class name. Now the class name has changed.
class CsvImportUploaderUploader < CarrierWave::Uploader::Base
permissions 0755
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
You can just keep using the same model name.
If you had a User model that would be converted from:
User => user
model.class.to_s.underscore just returns the class name itself as a string underscored which is "user" in this example.
If you want to keep everything as it was just write it literally:
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
"uploads/user/#{mounted_as}/#{model.id}"
If you don't care about the name, things will just be store in a different folder.
If you have a User model and changed it to a Customer model it changes like this:
"uploads/user/#{mounted_as}/#{model.id}"
"uploads/customer/#{mounted_as}/#{model.id}"
As you can see, they will just be store in a different folder. All your links should still keep working.
I have some meta-programming that condenses multiple direct S3 upload processes into a single controller. Then, those actions are shared across many models. To accomplish this, among many other details, I need to know the column name of a given models uploader. I facilitate this by having an 'uploader_name' method in each of my models that use the shared actions. For example, I have an Expense model that has a receipts uploader...
def uploader_name
'receipt'
end
mount_uploader :receipt, ReceiptUploader
So, now I can call Expense.new.uploader_name to return a string, or in a shared action I would use #obj.send(#obj.uploader_name) to get the uploader object (where #obj is any one of the affiliated models using the shared actions). This works fine. However, I think I can clean it up. One way that would help me refactor is not needing the uploader_name method. Or, being able to use a single uploader_name method in a shared module that is able to dynamically determine the column name of the uploader.
Is there a method within Carrierwave where I can access the column name on a models uploader without know what the uploader is called? Since the module is shared across multiple classes, i have to figure it out dynamically---I have read through the carrierwave, but not finding a solution.
Something like this...for example:
obj = self.class.name
obj.new.uploader # would return the mounted :receipts uploader
obj.new.uploader_column # would return the uploader column, in this case :receipt
There are a few methods provided by the uploader class. So, to solve this I just delegate the :mounted_as method from the uploader to the class that calls it. Then, without knowing the name of the actual uploader I can just call self.mounted_as.to_s to return the name of the uploader.
So, for a User model with an avatar uploader I do this.
class User
mount_uploader :avatar, AvatarUploader
delegate :mounted_as, to: :avatar
So, if I call #user.mounted_as I get :avatar. Or, more importantly...if I call self.mounted as I get :avatar when self is a User. I have a module that is shared between all models that use an uploader. In that module I include
def uploader_name
self.mounted_as.to_s
end
Now, I can do some meta-programming since I do not know who self is, and I do not know what self's uploader is called. But, now I can get access to both dynamically. This is helpful because I can share one uploader controller and one uploader form across multiple classes who use an uploader.
I can also do things like pass accepted extensions to the form input (see html5 accepts option) by simply grabbing the extensions in the uploader's extension_whitelist method.
self.send(uploader_name).extension_whitelist
# this is dynamically getting #user.avatar.extension_whitelist
# or #company.logo.extension_whitelist
I can also set uploader attributes using, for example...
obj.send(obj.uploader_name).content_type = 'image/jpeg'
# this is dynamically setting #user.avatar.content_type = 'image/jpeg'
# or #company.logo.content_type = 'image/jpeg'
obj.class.uploaders.keys.first
=> :receipt
I'm new to ror and paperclip.
I use paperclip to upload file, and I wonder how does paperclip determine the file id. For example in my User model, I add paperclip attachment "has_attachment_file", then I find that in database(I use sqlite3) there are four new columns in table "User" including file name, file type, uploaded time and file size. However I can't find the file id this column as I can retrieve from user.file.id. Where does paperclip store this things?
The attached file isn't stored in relation to the User — it's stored directly on it. That's why your User table has the extra columns, and why the file doesn't have an id.
If you want a User to have many files you will need to model them separately and use Rails' has_many. Something like:
class User < ActiveRecord::Base
has_many :images
end
class Image < ActiveRecord::Base
has_attached_file :file
belongs_to :user
end