And Your mileage may vary.
Notice 2: if you counter last image deletion bug or all images deletion issue, refer to this github issue for fix.
TL;DR. Jump to fully completed sample codes on Github.
In this blog post I am going to demonstrate how to implement multiple images uploading related features by using CarrierWave and PostgreSQL Array, and I am going to illustrate the technique in the context of a sample gallery application.
To be specific about the features, we are going to implement the following ones:
- Create a new gallery by uploading multiple images
- Upload more images into existing gallery
- Delete specific image from existing gallery (one at a time)
And roughly I am going to build this sample application in the following way:
- Use Rails 4.2.5 as the overall framework
- Use CarrierWave as the gem for handling multiple files uploading. And I am going to use the master branch, since according to the documentation, this feature is only enabled on the master branch
- Use PostgreSQL as the database, and particularly exploit the convenient
arraytype supported by PostgreSQL for storing a sequence of "images"
- Use Amazon S3 for storing the actual images uploaded
- Use Slim as the template engine and some HTML5 features, particular the <input> multiple attribute (eg.
<input type="file" name="imgs" multiple>)
And now let’s build this application step by step.
Step 1 Setup the Rails application
First let’s run
rails new sample-gallery-app-with-carrierwave to generate a new Rails applicaiton which we are going to work on.
And inside file
Gemfile, I specify the Ruby version to
2.3.0 by adding
Next let’s remove gem
sqlite3, and add following gems
And now let’s configure
config/database.yml to use
postgresql instead of
Finally, let’s run
bundle to get everything installed.
Step 2 Configure CarrierWave
Let’s create the initialization file
config/initializers/carrier_wave.rb and copy & paste in the example configuration from the official documentation.
You will need to replace sample credentials with yours.
And then Let’s generate our image uploader by calling
rails generate uploader Image, this should generate a new file at path
For this newly generated uploader, let’s change the storage from from
:fog (change line
storage :file to
Step 3 Scaffolding the basic
Now we have the our uploader
ImageUploader, let’s could go ahead scaffolding out our application.
rails g scaffold gallery title:string, and add
mount_uploaders :images, ImageUploader into the Active Record class, so that our
/app/models/gallery.rb looks like
Then lets create the images related migration by calling:
rails g migration AddImagesToGallery
And in the generated migration file, let’s write
This is how we add a array column
images to our galleries table for holding images.
Next let’s run
rake db:migrate and
rake db:setup to get our database updated.
Step 4 Implement create gallery feature
app/views/galleries/_form.html.slim file to add a multiple files field to the form.
Then let’s edit the
#gallery_params method of
GalleriesController to accept multiple images.
Next let’s edit the
show views to display the images we uploaded.
Let’s add the following codes into
And also add the following codes into
Now let’s start our Rails application and hit
http://localhost:3000/galleries/new to create a gallery.
After creation you should see something like the following screenshot when visiting
Step 5 Implement add more images feature
In step 5 let’s modify our routes, and nest an images resources under galleries resources, so that our
config/routes.rb file should look like something below
And now let’s generate the images controllers by calling
rails generate controller Images.
Then let’s write the actual codes responsible for adding more images into existing gallery.
And as you could see in the codes, when we need to add more images we simply add more images into the array attribute , and save the gallery object afterwards.
Now let’s modify the
show view to take advantage of this
ImagesController by adding the following codes
Now we let’s visit
show page of a single individual gallery, and we should be able to use the form there to add more images to existing galleries.
Step 6 Implement remove single image feature
Now let’s implement the remove single image feature.
Firstly let’s update routes to
The let’s implement the actual
#destory action of
ImagesController, so that the controller should looks like this:
As shown in the codes, when we want to delete certain image, we first remove the image from the array, then delete the image from S3, and lastly re-assign the modified images array back to gallery object.
Now let’s modify our
show view to use this action.
Let’s modify the code block we used to display the images to
Now when you visit a gallery, you should see something like following screenshot
Now you have completed the tutorial, and finish the three features we set to complete, you are good to go ahead refactoring those codes so that you could put them into productions.
You should move the add/remove related codes into two service classes, add some validations here and there, enhance the error messages, improve the front-end user experience, and make the codebase more robust, but they are out of the scope of this blog post, thus not covered here.
That’s all for this post.
Till next time.