Upload Files with Ruby

Uploading files in Ruby should be as easy, straightforward, and as fun as the language itself. Here’s my simple recipe to demonstrate exactly that.

First things first: this isn’t a Ruby on Rails recipe. I’ll make one of those in due course. This is a plain, simple, pure Ruby demonstration. I’ll use the open source Filestack SDK, which we’ll use to connect to Filestack’s Software-as-a-Service (SaaS) API. You can follow along with a free account if you don’t already have an account.

Our problem is this: using nothing but the Ruby programming language, we want to upload a file from the same machine where the code is running to… well, how shall we define the “up” in our “upload”? For many years, a file upload would be pretty simple. We had a physical computer acting as a web server sitting on a rack in a room somewhere. Our computers (or our users’ computers) were the “down”, and that server was the “up”. Users would “download” a file when it moved from that server to their computer. They would “upload” a file when they selected one from their computer and sent it to that server. It’s OK to keep that mental model as we accomplish a similar task today, but it may help to understand how many more steps are happening these days.

Filestack’s simple “upload” process can be exactly that: users select a file on their computer, and it goes from there to the cloud storage Filestack provides. There’s a lot more power that can be unleashed if you want it though, like a massively distributed ingest process. You know how CDN’s have servers spread out all around the world to make sure you get a copy of a file from a server close to you? Same thing, but in reverse. Servers close to you (and your users) around the world are sitting close at hand, ready to “ingest” these uploads.

You can also ingest files from users’ Instagram, Facebook, Dropbox, and other service providers. Whether you’re using Ruby or any other language on your back end, you’ll probably need to render HTML, CSS, and JavaScript at some point to the user. In that case, you wouldn’t need to do what we’re doing here using the Ruby SDK; you’d just include our File Picker using two lines of code (one is an HTML <script> tag to import the JS, and the other is the JS that tells that Picker to display on your page).

Whether you’re uploading files from a server to an S3 bucket, from a user’s cell phone to your default Filestack storage, or sort of side-load from a user’s Dropbox to your own, we’ll use our APIKEY to connect and we’ll grab our files by File Handles to do stuff with them.

It just feels right to call it an upload because that’s how simple it is to your users and heck, even in your code. Calling it an asynchronous, resume-able, massively distributed ingest and replication process with instant high availability through automatic workflow rules with Artificial Intelligence and processing with Machine Learning via a REST architecture makes it sound much harder than it actually is. Here, I’ll show you:

$ gem install filestack

Don’t type the dollar sign ($) when you enter that command in your terminal. That would be silly.

MVP

Let’s create a Minimally Viable Product. With the gem available on my system, it’s ready to use in my code. I’ll create a file called upload.rb and require the gem:

require 'filestack'
client = FilestackClient.new('MYAPIKEYHERE')
filelink = client.upload(filepath: 'the-great-ruby.jpg')
puts filelink.url

That’s really it for me. Of course, for you, you’ll need to do a couple things to get this to run. First, substitute your own APIKEY. You can get this by logging in to https://dev.filestack.com/ and looking at the drop-down list on the upper-right-hand side of the page. The second thing you’ll need is that file (or any file, really) so you have an actual thing to upload.

Interactive Inspection of Our Client

We’re done here. But wait, there’s more! Let’s do this same thing in IRB so we have live objects we can inspect. If you didn’t grab the filestack gem earlier, do that now. Fire up IRB:

$ irb

That will drop you into the Interactive Ruby shell, where we’ll issue the command to :

2.5.1 :001 > require 'filestack'
=> true

IRB is showing a prompt with the version number of the Ruby I’m running; yours may differ. Each command gets its own number, like :001 in that case. After the > you can see what I’m typing, and after I press enter I see the result called out by a fat arrow => like that. Because successful functions return true, that’s what we see when our command works here. We’re really just typing the same commands from the script above, one at a time interactively:

2.5.1 :002 > client = FilestackClient.new("TheAPIKEYofDestiny2001AkEyOdDDYseY")
=> #<FilestackClient:0x00007fc5278d6d70 @apikey="'TheAPIKEYofDestiny2001AkEyOdDDYseY'", @security=nil>

I totally made up that APIKEY. Use yours instead. The result of calling this in IRB is the same as the result of calling it in our script from the example earlier. The difference here is that we’re stepping through this manually, one step at a time. That means we can do something magical right now, as though time itself has stopped. We can inspect the client object:

2.5.1 :003 > client.methods
=> [:zip, :upload, :apikey, :security, :transform_external, :get_file_info, :multipart_start, :create_upload_jobs, :upload_chunk, :run_uploads, :multipart_complete, :multipart_upload, :chunk_job, :run_intelligent_upload_flow, :create_intelligent_generator, :run_intelligent_uploads, :upload_chunk_intelligently, :get_generator_batch, :create_upload_job_chunks, :bad_state, :change_offset, :make_call, :get_url, :send_upload, :to_json, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :instance_of?, :kind_of?, :is_a?, :tap, :instance_variable_get, :public_methods, :instance_variables, :method, :public_method, :define_singleton_method, :singleton_method, :public_send, :extend, :pp, :to_enum, :enum_for, :<=>, :===, :=~, :!~, :eql?, :respond_to?, :freeze, :inspect, :object_id, :send, :to_s, :display, :nil?, :hash, :class, :singleton_class, :clone, :dup, :yield_self, :itself, :tainted?, :taint, :untrust, :untaint, :trust, :untrusted?, :methods, :frozen?, :singleton_methods, :protected_methods, :private_methods, :!, :equal?, :instance_eval, :==, :instance_exec, :!=, :__id__, :__send__]

I love that so much! 😀 These are all of the methods the client object presents for interacting with the Filestack API. Keep in mind that these include both the methods lovingly crafted by Filestack’s Engineers, and also any methods inherited from parent objects all the way up to the One True Object Ruby exposes natively.

Want to play with different versions of Ruby? There’s a script for that. https://rvm.io/

Now that you have a file handle, you can store it, pass it in a URL to get a transformation on the CDN, and use it to reference the file for display in one of Filestack’s viewers if needed.

Read More →