Serverless File Uploads for Ruby on Rails
19 Minutes to Integrate

Overview

This guide will walk you through the process of creating a simple blogging application in Ruby on Rails powered by Uploadcare for uploading images and generating previews.

It will take you about 19 minutes to get a fully functional web app that accepts image uploads for blog posts.

Here is a screenshot of what we are going to build:

Demo Blog Screen Capture

Setting Things Up

Uploadcare Account Keys

The first thing to get you started is an Uploadcare account. So Sign Up if you haven’t done so before. Create a new project on your dashboard or navigate to an existing one; go to the “API Keys” section and find your keys.

Installation

Let’s create our demo application and add the Uploadcare integration:

rails new uc-demo-blog -T

Note, the -T flag tells Rails to generate the new application without the default test suite; we’ll skip the suite for this guide.

Executing the command creates a Rails application in the uc-demo-blog directory and installs the dependencies mentioned in your Gemfile. Now, switch to your new app’s directory:

cd uc-demo-blog

Next, integrate Uploadcare. Open your Gemfile and add the following line:

gem 'uploadcare-rails'

The last step left here is running install:

bundle install

Configuration

In Ruby on Rails, you use the uploadcare.yml file to configure your Uploadcare integration. Run the command below to generate it or create the file manually in your project’s config directory:

bundle exec rails g uploadcare_config

Here’s an example of how your uploadcare.yml may look like:

defaults: &defaults
public_key: "YOUR_PUBLIC_KEY"
private_key: "YOUR_SECRET_KEY"

# instances of widget initialized for you on page load
live: true

# cache files json dumps to prevent calling to server if it posible
cache_files: true

# cache groups json dumps to prevent calling to server if it posible
cache_groups: true

# store file or group after model is created or updated
store_after_save: true

# deletes file or group after model object is deleted
delete_after_destroy: true

...

development:
<<: *defaults

test:
<<: *defaults

production:
<<: *defaults```

The config won’t be valid unless you set the public_key and private_key params to your account Public and Secret API Keys respectively.

Creating the Demo Application

Now, let’s enhance our app by adding a data model, views, and a controller. We’ll briefly go over the major points, to dig deep see this demo sources.

Model

When blogging, you make posts. So, our demo app requires a Post model with the:

  • title attribute of type string
  • body attribute of type text
  • file attribute of type text

Let’s generate the model and migrate your database:

rails g model Post title:string body:text
rails db:migrate

Now, we need to handle single-file uploads; update the Post model you just generated to look like this:

class Post < ApplicationRecord
  has_uploadcare_file :file
end

If we were to go with multi-file uploads, we’d declare has_uploadcare_group instead.

Views

Great, we can now focus on views. If you want to learn more about the Bootstrap components we use, refer to Bootstrap documentation.

To handle uploads, we’ll integrate File Uploader, a widget that allows picking files, defining upload sources, previewing, cropping and otherwise editing images.

To get the widget from Uploadcare CDN and include application-wide settings put the following in the <head> of application layout:

<!-- app/views/layouts/application.html.erb -->

<!DOCTYPE html>
<html>
  <head>
    <title>Demo Blog</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>

    <%# Include and config uploadcare widget %>
    <%= include_uploadcare_widget_from_cdn version: "3.x", min: true %>
    <%= uploadcare_settings %>
  </head>

Now let’s see how we can use the Uploadcare gem in views. Let’s use our index view to display all posts:

<!-- app/views/posts/index.html.erb -->

<div class="jumbotron">
  <h1 class="display-2">Recent Posts</h1>
</div>
<div class="posts-grid">
  <% @rows.each do |row| %>
    <div class="row">
    <% row.each do |post| %>
      <div class="col-md-4 col-sm-12">
        <div class="card" style="width: 20rem;">
          <div class="card-body">
            <% if post.file? %>
              <div class="image_wrapper">
                <%= image_tag post.file.url(preview: '150x150') %>
              </div>
            <% end %>
            <h4 class="card-title"><%= link_to post.title, post_path(post) %></h4>
            <p class="card-text"><%= truncate(post.body, length: 150) %></p>
          </div>
        </div>
      </div>
    <% end %>
    </div>
  <% end %>
</div>

There is couple of things going on here. First, we use post.file.url, which is a CDN URL, to display a hosted image within our image_wrapper block. Secondly, we pass the preview argument so that listed posts feature an image thumbnail.

Likewise, add a new view for creating new posts:

<!-- app/views/posts/new.html.erb -->

<div class="jumbotron">
  <h1 class="display-3">Add Post</h1>
</div>
<% if post.file? %>
  <div class="image_wrapper">
    <%= image_tag post.file %>
  </div>
<% end %>
<%= form_for post do |f| %>
  <div class="form-group">
    <%= f.text_field :title, placeholder: 'Title', class: 'form-control form-control-lg' %>
  </div>
  <div class="form-group">
    <%= f.text_area :body, placeholder: 'The body of your post', class: 'form-control form-control-lg', rows: '3' %>
  </div>

  <div class="form-group">
    <%= f.uploadcare_uploader :file %>
  </div>

  <%= f.submit 'Add Post', class: 'btn btn-primary btn-lg'%>
<% end %>

And a view named show to show a created post after form submission:

<!-- app/views/posts/show.html.erb -->

<div class="jumbotron">
  <h1 class="display-3"><%= @post.title %></h1>
</div>
<% if @post.file? %>
  <div class="image_wrapper">
    <%= image_tag @post.file %>
  </div>
<% end %>
<p><%= raw @post.body %></p>

Controller

So far so good. Time to add a controller. Let us generate that:

rails g controller Posts

Edit your PostsController to look like below:

class PostsController < ApplicationController
  before_action :set_post, only: [:destroy]

  def index
    @posts = Post.order('created_at')
    @rows = [[]]
    @posts.each do |post|
      if @rows[-1].length < 3
        @rows[-1] << post
      else
        @rows << []
        @rows[-1] << post
      end
    end
  end

  def new
    @post = Post.new
  end

  def create
    @post = Post.new(post_params)
    if @post.save
      redirect_to post_path(@post)
    else
      render :new
    end
  end

  def destroy
    @post.destroy
    redirect_to posts_path
  end

  private

  def post_params
    params.require(:post).permit(:title, :body, :file)
  end

  def set_post
    @post = Post.find(params[:id])
  end

end

We added a few actions here:

  • Listing posts in order of creation
  • Creating and saving a post
  • Deleting a post

As a final step, configure your route file to point to your controller:

# config/routes.rb

Rails.application.routes.draw do
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  resources :posts
  root to: 'posts#index'
end

That’s it! You can fire up your rails server and point your browser to http://localhost:3000. You should now be able to play with your app: see posts listed on the home page, add new posts, etc.

Conclusion

In this guide, we’ve covered the basics of how to easily integrate file uploading in your Rails application with Uploadcare. If you want to learn more about Uploadcare in Ruby on Rails, check out this Github repo.

We’re always happy to help with code, integration, and other stuff. Search our site for more info or post your question in our Community Area.