What

This recipe will walk you through moving your Rock Person Images (Profile photos) out of the database and into Cloud storage... but not just any cloud storage. CLOUDinary storage!

Why

By default, Rock stores person images within the database and this can cause several issues:

  1. Over time the number and size of these images can bloat your database, making it much larger than it needs to be... especially for large churches with 50k or more people records.
  2. You have very little control over the size of the images that staff (via internal Rock) or the persons themselves (via the /myaccount page or a Photo Request email) upload. With crazy resolutions of modern phones, a cell phone image can be anywhere from 1-7MB (or more) these days, storing such large photos in your database is Not Cooltm

While there are several cloud storage providers that can easily store your Rock images, CLOUDinary is unique among them in that it allows you to do some very useful things with the images (resize, trim, compress, etc.) vs. simply storing them as-is on a remote file system. Need an example? Fine. Imagine someone comes along and uploads this photo as their profile pic... ProfileBig.jpg Original 1.3MB 3000x2000 image

On default Rock, this will make a terrible Profile pic, because the person is so small in relation to the rest of the image, and even though Rock lets the person crop the image somewhat, they will rarely get it right. Now imagine that as soon as the person uploads that image, Rock shows this instead:
ProfileCropped.jpg Stored 21K 550x550 image

Notice how even before the person has saved the image, Cloudinary has found the face, cropped to 550x550, and compressed it to a tiny size... all without the user having to do anything or operate the "crop" controls? on! Now that you're convinced, let's get going.

How

This is a detailed recipe, but not difficult if you follow the steps and read instead of skim. That said, I first need to clarify a few things:

  • This recipe details the use to two plugins available in the Rock shop: Cloudinary Storage Provider and Storage Mover.
  • Both of these must be purchased at a non-trivial cost (and are worth every penny in my opinion), but I want to stress that I am not affiliated with these plugins in any way and I have no financial interest in them. I just find them extremely useful and even essential to running Rock in our organization.

While I'm going to give you step-by-step instructions, this is one of those recipes you might want to read through once before you start performing the steps so you know what's involved (and if you even want to do it).


1. Set Up Cloudinary

This is the first step in the process as you must have a Cloudinary account before you purchase and configure the storage provider in Rock. Luckily this is low risk because Cloudinary offers an incredibly generous FREE account that will likely give enough "credits" for the majority of churches' normal usage without paying a dime. That said, we find Cloudinary so useful and essential here that we'd gladly pay for it if the free plan ever went away.

  1. Go to https://cloudinary.com and click the large SIGN UP FOR FREE button.

  2. While filling out your information, consider changing the random "cloud name" with one of your choosing. For example, we used the-crossing as our cloud name. You can also leave the default and change it later, but it's best to start off with the desired name. cloud_name.png

  3. I encourage you to read up on the free plan so you know what it gives you. It should provide more than enough resources for all but the largest of organizations.


2. Purchase & Install Plugins

  1. From your own Rock instance, go to Admin | Rock Shop and grab both the Cloudinary Storage Provider and Storage Mover plugins. I highly recommend that you read through the (short) documentation for each before purchasing, just to be sure you understand what they do and how they operate.

  2. After installing, configure the Cloudinary provider by going to Admin | System Settings | File Storage Providers and click your new Cloudinary Provider. storage_provider_config.png

  3. Fill in the information required, which can all be found in your new Dashboard at cloudinary.com. cloudinary_dashboard.png


3. Configure Cloudinary

We need to get some things ready on Cloudinary for the purpose of storing our soon-to-be-moved Person Images. It's important to understand the goal here, which is to move Person Images out of the Rock database and at the same time, "transform" them to be stored more efficiently (optimized), cropped to the square aspect ratio Rock uses for these images, and (coolest of all) focus on any faces it can find in the image. That's right... regardless of the picture staff or users upload to Person Profiles, they will end up in Cloudinary "stored and transformed" with the settings we desire.

  1. In your Cloudinary account, click Media Library, then add a new folder. media_library.png Give it a name like rock-person-photo or similar. This is where Rock will store Person Images once everything is configured.

  2. Go to Transformations and click Create a new transformation... Fill out the form as follows: cloudinary_transform.png
    You can of course use differnet settings, but these have worked well for us. What they are saying is:
    • Crop the image to 550x550 (we've found that to be a good dimension for person photos as they are displayed pretty small on the profile page, anyway.)

    • Use Fill crop mode, which -- along with Faces (Auto) Gravity -- provides a good "find any faces" result. Thumb is another potential crop mode if you really want to zoom in on faces, but I found it sometimes completely cropped-out faces in a multi-face photo if they weren't close enough together. We found Fill to be the best compromise crop mode (and keep in mind that the person doing the upload can still use Rock's own tool to crop further during upload). You can read about the various crop modes in the Cloudinary online docs to find out how they behave.

    • Compress the image with "economy" mode, which will make the images very small at the expense of quality, but still pretty good looking on a Profile page. Our philosophy is: these are person images that show on profile pages and don't NEED to be high quality, and we just want them to be small and fast...and that's exactly what ECO mode does. We typically see most person images end up between 10-20k. Let that sink in for a second... if a 2MB image is uploaded to the person profile, Cloudinary will transform it on the fly and store a cropped 20k image... and find the face(s). How crazy is that?

  3. Save the Transformation and give it a name like rock-person-photo or similar.


4. Configure File Type

Now we have to (re)configure the Person Image File Type in Rock.

  1. Go to Admin | General Settings | File Types and click on the Person Image file type. Assuming you haven't modified this file type before, the Storage Type should be Database. This is where Rock is currently storing person images.

  2. Change the Storage Type to Cloudinary Blob Storage and enter the Folder Name and Transformation Name you created on Cloudinary above. It's important that you enter them exactly as they are named in Cloudinary or things won't work as expected. file_type.png (If you don't see Cloudinary Blob Storage as an option in the drop-down, this means you have not installed the Cloudinary Plugin from the Rock Shop.) What these settings are saying are: 1. From now on, store person images in Cloudinary, 2. In this specific folder, and 3. perform this Named Transformation "on the way up." Note that because the images are being transformed "on the fly", the original image is discarded and only the transformed image is stored. This could be undesirable in other contexts (file types) but it's exactly what we want for storing our person images.

  3. Save the File Type.

It's important to know that as of this moment, any new person image added to Rock will end up in Cloudinary. Go ahead and add or change the image on your own record, and verify that it shows up in the folder you created in Cloudinary. Notice that the image has been transformed (cropped, optimized, resized) and that the original filename gets replaced with a random string that Cloudinary creates. This is actually a Good Thing we'll talk about later.

You also may be wondering what happens to existing images? Great question. The good news is... nothing! Rock is smart enough to know which provider any particular image is stored with, so right now you have a "split" File Type where existing person images are still sitting in the database, while all new ones (as of performing the steps above) go to Cloudinary, and that "fork" is maintained forever... at least until you move the images to a new provider. Hey, let's do that!


5. Storage Mover

Now that we have new Person Images storing to Cloudinary, it's time to move all the old ones still in the database. With the Storage Mover plugin this is very easy. Assuming you've already installed the plugin, follow these steps:

  1. Go to Admin | Installed Plugins | Storage Mover. The first thing you will see is a warning about making sure you have a backup before proceeding.

    Important: Before transitioning storage providers please ensure you have a up-to-date backup of your files and database.

    Please heed this warning and only continue if you indeed have a backup. While I've never seen this plugin misbehave, there are far too many variables in individual organization's data to assume it will work perfectly for everyone. You have been warned!

  2. In the File Type drop-down choose Person Image. After making the selection you should be on a screen that looks like this:storage_mover.png
    Notice that it shows Cloudinary as the (current) storage type for this file type, because we changed it to that earlier in this process. If you do not see (current) after Cloudinary but after Database instead, stop and do not proceed. This simply means you skipped over some important stuff earlier and didn't change the Storage Provider on the Person Image file type to Cloudinary. Until you fix that you won't be able to move your person images to Cloudinary.

  3. Make sure you select Database for Source Storage Type (it should be the only option at this point) and change Max Files to Move from 1000 to something low, like 10. This will only move 10 items so you can verify things are working as expected. After making your form the same as the above image, click MOVE

  4. If all goes well, you should see a progress bar as files are moved ending with a screen like this: storage_mover_done.png

  5. Head back over to Cloudinary and drill down to your rock-person-photo folder under Media Library. Verify that you see the person images you just moved there. Assuming all looks good, you can go back to Rock and repeat the Storage Mover process.

    I recommend that you only do about 1000 files at a time and just work in batches until you get them all moved. Note that I have seen some flaky UI behavior when trying to use the Move Additional Files button after a successful move, so if you see something weird just restart Storage Mover from Admin | Installed Plugins and start over fresh for that batch.


That's it!

If you've made it this far, you should now have all of your Person Images stored in Cloudinary and a lot more free space in your database. I want to wrap up with a few odds & ends:


Image Security

Note that these images stored in Cloudinary are technically "public", meaning they are sitting on a web server that doesn't need authentication to see them. Remember how we saw earlier that images get uploaded with a long, random file name? This is why it should not be a big deal to have these photos at public URLs, because they are so unpredictable (un-guess-able). A file sitting on Cloudinary will have a URL that looks something like this:

https://res.cloudinary.com/ddsxkptr4n/image/upload/v1565751430/rock-person-photo/jeqii4c2ype7gb3ewtxs.jpg
So, even if someone looks at the source of the webpage or right-clicks a person image to see its name, they will NOT be able to "poke around" trying other similar filenames and get any hits to other images... it's just statistically impossible (ok, very very VERY unlikely). And even if there were a coincidental hit to an existing image, the photo stored there is not associated with a person's name, anyway.

Purists would call this "security by obscurity" and dismiss it as "not secure" (and they'd be technically correct), but for us the nature of this data (pictures devoid of person names) and the random nature of the URLs these images live at are a tradeoff we're willing to make. That said, there is a way to secure Cloudinary URLs, but that is beyond the scope of this article and adds a lot of complexity, and I'm not even sure if the current Cloudinary Plugin would even support it. If you do manage to figure out how to secure these Cloudinary images, please leave a comment!


Max Image Size

The Cloudinary Free plan has a maximum image size of 10MB, which is pretty large... but not large enough! Someone will inevitably try to upload a file >10MB and today, this causes whatever UI the person is on to get a nasty error, like this: Exception.png The problem is that this error currently cannot be trapped, and even if you're only storing a 100k file after it's transformed, the >10MB image still has to get to Cloudinary first, and that's what Cloudinary sees as the file size. The fix for this is for Rock core to add a Maximum Image Size property to a File Type, so that the Admin can define (per File Type) the largest image to allow, and exceeding that limit would present a nice error stating the max size in the UI. If you'd like to see such a feature added, please vote for it here. Voting it up is the only way such a feature will be added.


Duplicate Images

As you implement this and start looking at the photos stored in Cloudinary, you might see duplicate images of the same person. This is normal and expected, because the instant the person uploads their image, Cloudinary transforms and stores it... then the person clicks "crop" in the Rock UI which saves another copy of the image. If the person then decides they don't like the look of the image they just uploaded, they may try another, and another... all ending up in Cloudinary.

The good news is that you don't need to worry about these. The nightly Rock Cleanup job will find these orphaned images and clean them up for you. Boom!