Multiple image uploads with Carousel in Rails App - Stimulus
Published 11 April 2022
Tutorial
Carousels are a fantastic way of showcasing media in an app. For a long time, implementing this in Rails was rather difficult. Thanks to StimulusJS (which in my own words, gives Rails apps superpowers), we can easily build this feature out.
Please follow along to learn how to go about this.
First off, your resource needs to allow for multiple image uploads. Assuming you have a resource named Article, you would navigate to the article.rb model and include:
Please follow along to learn how to go about this.
First off, your resource needs to allow for multiple image uploads. Assuming you have a resource named Article, you would navigate to the article.rb model and include:
class Article < ApplicationRecord # Associations has_many_attached :photos # Optional validation validates :photos, blob: { content_type: %w[image/png image/jpg image/jpeg], size_range: 0.1..5.megabytes } end
You can read more on Active Record associations here.
After setting up the association, you will want to allow the resource attribute to be saved in the model. We do this in the articles_conttroller.rb:
def article_params params.require(:post).permit(:title, :description, :photos => []) end
In the article form, you want to allow users to upload the multiple images by adding the following:
<div class="form-field"> <%= form.label :photos %> <%= form.file_field :photos, :multiple => true %> </div>
From there, we need to install Stimulus Carousel:
yarn add stimulus-carousel
In your app/javascript/controllers/index.js, you will need to import and register the component for it to work in your app:
import Carousel from 'stimulus-carousel' application.register('carousel', Carousel)
The carousel component uses SwiperJS underneath the hood. For this reason, you will have to import Swiper’s CSS in your app/javascript/packs/application.js. I personally have included the application.html.erb layout:
<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script> <!-- Initialize Swiper --> <script> varswiper= new Swiper('.swiper-container', { navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }, }); </script>
I am not looking for much customization of the Swiper stuff.
When all this has been set up, you will need to navigate to the show (app/views/articles/show.html.erb ):
<% if @article.photos.attached? %> <div data-controller="carousel" class="swiper swiper-initialized swiper-horizontal swiper-pointer-events" data-carousel-options-value="{ "navigation": { "nextEl": ".swiper-button-next", "prevEl": ".swiper-button-prev" } }" > <div class="swiper-wrapper"> <% @article.photos.each do |photo| %> <div class="swiper-slide swiper-slide-prev flex items-center justify-center" style="width: 992px;"> <%= link_to url_for(photo) do %> <%= link_to url_for(photo) do %> <%= image_tag url_for(photo), :alt => "#{photo.filename}", :class => "w-fit flex justify-center items-center" %> <% end %> <% end %> </div> <% end %> </div> <%# Swiper Buttons %> <div class="swiper-button-next" tabindex="0" role="button" aria-label="Next slide" aria-controls="swiper-wrapper-3614d810d7f2d3fb5" aria-disabled="false"></div> <div class="swiper-button-prev" tabindex="0" role="button" aria-label="Previous slide" aria-controls="swiper-wrapper-3614d810d7f2d3fb5" aria-disabled="false"></div> <span class="swiper-notification" aria-live="assertive" aria-atomic="true"></span> </div> <% end %>
And there you have it, a working carousel with multiple uploads.
We could improve this by allowing for looping of the images when the last image is loaded on the show view or even deletion of a single image from the array of images but that could be an improvement we tackle in another tutorial.
Thank you for following along and happy coding.
Tags:
Rails, Stimulus JS, ActiveStorage