Organise Active Storage files for use in other systems? - ruby-on-rails

Active Storage stores uploads in a file structure like so:
This is great if the rails app is the only software that needs to use these files.
But what if the app simply serves as a means to upload the images to S3 so that some other (completely separate) service can consume them?
The problem being, other developers wouldn't be able to make any sense of the directory and files, since they're labelled in a way rails can understand, but which a human cannot (e.g. what does folder named "O2" mean?).
Is there some way to ensure uploads are stored in a human-friendly way? e.g. each folder could be a user_id, with their assets inside? (or similar)

As far as I remember, you would have to implement an own service that somehow replace the key used to something else (e.g. S3Service), or patch ActiveStorage to create the key itself in a different way. I am not sure that this would suffice though, as the key is most likely used for other critical functionality outside of the Service.
Alternatively you might poke in ActiveStorage::Blob to fiddle with the key. That said, ActiveStorage does not support what you'd like out of the box and you would have to take the risk of messing with its internals.
A solution to the problem (but not answer to you question) might be implementing an API as outlined in the comments to your question.

Related

active storage / clean files url

Multiple question around the same issue, the way active storage returns file urls
For now with the default setup, the following (cloud or local), returns somehow the following :
_domain/_path/_superlong_hash/_original_filename._ext
Given paperclip or many other existing gems, the _path/_superlong_hash/_original_filename._ext part is in hand to be customised, could end up in a clean url for any files
Meaning by that :
is there a way to "proxy" the _path with something more custom ?
is there a way to avoid the _superlong_hash ?
is there a way to customize the filename on the fly (or on uploads) ?
To make it a one-liner, how one would customize the files urls ?
I've seen here and there people ending up creating custom controllers to serve file with decent urls, but let's admit this is a no go (IMHO)
I hope that ActiveStorage proves me wrong soon, but at the time of writing Rails 5.2, the straight answer seems to be that you have to go with your 'no go' option, hacking your own controllers together and heavily patching ActiveStorage to expose files.
For proxying see:
https://github.com/rails/rails/issues/31419
https://github.com/rails/rails/pull/30465
especially georgeclaghorn responses are interesting
For renaming file:
#user.avatar.blob.update(filename: 'NewFilename.jpg')
Manipulating the _superlong_hash / url
I have no good answer for this one. Although ActiveStorage makes it breathtakingly easy to upload (and somewhat easy to manipulate) files it takes Rails opinionated software philosophy to the edge, making it quite difficult to bypass it's obscurity by abstraction approach to url generation. ActiveStorage provides no built-in methods to do rudimentary things like permanent or direct links to files and variants once generated. File/image caching and nice urls seem therefore not to be possible to accomplish out of the box with ActiveStorage at this point in time.

How to implement a rich text document store in Rails

I need a tiny (less than 100 total) document store in a Rails 3.2 app where a user can create, edit, save, and delete rich text documents (ideally including images and other attached items). There is no file system available. Everthing must go in PostgreSQL database tables. The documents will serve as system-wide email and message banner templates.
My approach has been CKEditor. But the ckeditor gem seems wired for attachments as files. Also, it does not provide create/update storage of the document itself, just attachments.
I know how to roll my own model/controller/view the CKEditor but surely there's a simpler way.
So what is the most direct way to my goal of the rich text document store? Is there a plugin or gem?
More CKEditor references: This thread makes it look like a major project, but it's 2 years old. This one makes it sound like the default, but no other document does.
More
Using S3, Dropbox as suggested are also nogo. As I said, data must reside in PgSQL tables. Good news: found the paperclip_database gem. Bad news: doesn't work seamlessly with the ckeditor gem. The main issue boils out to this bit in the source file database.rb:
def setup_paperclip_files_model
#TODO: This fails when your model is in a namespace.
Indeed it does, as in the Ckeditor::Asset model! Trying a monkey patch now. If anyone has already made these three gems work together correctly, I'll give you the bounty for a pointer!
Pretty sure CKEditor makes it fairly simple to edit database form fields, which is all you'd need for editing the document itself, correct?
As far as attachment storage, you can use paperclip to manage the attachments -- file storage is just the default. If you use paperclip, you can then use one of many storage options from there, such as Amazon S3 storage, Dropbox, or create your own.
Hope that helps.
The first thread you linked to has it correctly: you need to (find or) write a custom server connector, and configure CKEditor to use it. You can find the relevant updated docs here:
http://docs.ckeditor.com/#!/guide/dev_file_browser_api

What is the simplest Rails file upload method?

I've looked at the available options and it seems like everything is optimized for image uploading as display. I just need simple file upload and retrieval. Are there any good options?
Paperclip is a popular choice for uploading and sizing images, but you can upload any type of file with it (doc, zip, txt, pdf... anything). Highly recommended. https://github.com/thoughtbot/paperclip
I like carrierwave. It has built in support for s3, has no workaround for setting up apps on heeroku unlike paperclip.
I use Carrierwave for mine and have been happy with it. I am just uploading general files, not specifically images. It is easy to implement and has good advanced features if you need them later. It also integrates with Fog to make using remote storage sources (like s3 or rackspace cloud files) easy.
Carrierwave benefits:
With carrierwave, the attachment is a seperate model instead of an attribute on an existing model, which might make things cleaner to work with.
It comes with the ability to attach a file via url (user passes in a url to a file) instead of uploading with a form).
It comes with some sort of way to remember files across form validation failures, although I've never used this and I'm not sure how it's done... maybe with two forms and ajax?
It seems to have a more engaged and enthusiastic community around it, with more projects extending it.
For S3, they use fog instead of aws-s3, and fog has much more active development.
That said, paperclip is pretty great and is actively maintained, and might come with handier default image manipulation stuff, I'm not sure.

Pulling CSS assets (like background images) from the database in a Rails app?

I'm wondering if there's a way to store CSS asset paths, like background images, in the database so that they're customizable without accessing or rewriting the code. I've looked at some template engines, like liquid, but think they're a overkill for what I want to do. I only want a tiny bit of customization in my views between various deployments of the same app codebase, not anything for various users.
I've not looked much at Rails 3.1, but from what I understand the CSS assets are compiled and aren't static any longer, so -- does that mean I can write something like that into my CSS in rails 3.1 that pulls from the database? I usually deploy to Heroku and aren't sure if they're supporting 3.1 yet.
Anyone have any better strategies or ideas?
Storing binary files like images in the database can quickly become cumbersome. There was a time when we were storing user uploads like PDF's and such in the DB but it became unmanageable. We quickly moved it all over to S3 and made Paperclip store and retrieve the files there (encrypting the files before saving them to S3, and sending them over SSL since the files were potentially sensitive) and it made things much saner.
I'd say best bet for you is to use S3. Since
On heroku you have a limited
database size (depending on your
plan) and could quickly run out if
you're storing binaries there.
You can't dynamically save new files
to the filesystem on heroku, and
S3 is cheap as hell (and free for
most casual use) to store and
retrieve files.
EDIT based on your comment:
Ok I mis-understood the question. Either store the image path in the database or have the image stored with such a path & naming convention that the code itself can figure out where to get the image (which is what paperclip does). Both ways are acceptable. NOTE that SASS is not truly dynamic, you can't pull paths from the database and make the sass change on-the-fly. I've run into a similar situation and the solution was to make the CSS point to a background-image that was in fact a route in the application. In our instance we were able to change the image displayed based on the subdomain or domain of the incoming user, but you could just as easily display that image based on a session cookie that gets set before the views are rendered.
While SASS is compiled, after it's been generated it is static. The syntax, and 'dynamic' nature of it are just to make writing CSS easier.
What about using something like S3(Paperclip) + a "css assets" table/model?
That way in an "admin" page you can pull all of the possible CSS assets, allow someone to select a new one or even upload a new image to s3. This means you wouldn't have to actually rewrite any code just have an admin portal where they can select possible images.

Add a file to a database in a Ruby on Rails application?

I've only just started learning ruby on rails and I would like to create an application that will allow me to add files to the database. Currently, I'm developing the rails application using the Aptana plugin for Eclipse and the application is using the default sqllite db.
I have tried generating a scaffold with the following parameters: documents title:string file:varbinary. Then I do a 'rake'->'db'->'migrate'. When I migrate to localhost/documents and click on 'New Document' the application fails and displays an error.
What I would like to do is click on 'New Document', have a field that will allow me to browse for a document on my local computer, select the document and add it to the db on the rails application.
Paperclip is more recommended than attachment_fu these days. It is really simple and easy to use with your active record model.
Is it a particular kind of file you want to add?
I just ask because if it's not data of a kind that benefits from being in a database ( textual data might be searchable, binary data is not ) then you are much better storing it in the filesystem and serving it up straight - especially for stuff like images or video - rather than inserting it into a database and having to go through your application every time a user requests it.
I'm not saying that there aren't any reasons you might want to have a file in the database, but I treat that as a last resort and in ten years of web programming I've not come across a case where it was necessary.
I would highly recommend the attachment_fu plugin as this lets you create models with attachments pretty nicely, Paperclip plugin is another good one also!
If you have trouble deciding which one to use, as far as i can remember, Paperclip makes it easier for multiple attachments, such as an Album has many Photos, and Attachment_fu is easier for single attachments such as a User has one display picture.
We do something like this on a site I'm managing. Instead of storing these files in a database, I'd agree with the other posters here and recommend you try something like Paperclip.
One caveat: if you want access control, make sure that paperclip doesn't save your files somewhere under /public, where anyone could possibly access them if they knew the URL. Deliver files to the user via send_file in your controller.

Resources