April 8, 2025
Build a photo gallery in Rails with Cloudinary (free tier)
Scaffolding
rails g scaffold property name description:text
rails db:migrate
Setup Cloudinary
bundle add cloudinary
config/initializers/cloudinary.rb
Cloudinary.config do |config|
config.cloud_name = Rails.application.credentials.dig(Rails.env.to_sym, :cloudinary, :cloud_name)
config.api_key = Rails.application.credentials.dig(Rails.env.to_sym, :cloudinary, :api_key)
config.api_secret = Rails.application.credentials.dig(Rails.env.to_sym, :cloudinary, :api_secret)
config.secure = true
config.cdn_subdomain = true
end
EDITOR=vim rails credentials:edit
development:
cloudinary:
cloud_name: dxe1hjkoi
api_key: 361019726125669
api_secret: Cn6tHfSf019278367sZoO083eOI
config/storage.yml
cloudinary:
service: Cloudinary
folder: <%= Rails.env %>
config/environments/development.rb
config.active_storage.service = :cloudinary
Upload photos
app/models/property.rb
class Property < ApplicationRecord
has_many_attached :photos
end
app/views/properties/_form.html.erb
= simple_form_for @property do |f|
= f.input :photos, as: :file, input_html: { multiple: true }
app/controllers/properties_controller.rb
def property_params
params.require(:property).permit(:name, :description, photos: [])
end
Show photos
app/views/properties/show.html.erb
- @property.photos.each do |photo|
= cl_image_tag photo.key, height: 500, width: 1108, crop: :fill
Delete photos
config/routes.rb
resources :properties do
resources :photos do
match '/remove', to: 'properties#remove', via: 'delete'
end
end
app/controllers/properties_controller.rb
def remove
# We rely on the account to scope properties, but use your own logic.
@property = current_account.properties.find(params[:property_id])
@photo = @property.photos.find(params[:photo_id])
@photo.purge
redirect_to property_path(@property), notice: "Photo was successfully removed."
end
app/views/properties/_form.html.slim
.card-columns.mt-3
- @property.photos.each do |photo|
.card
.card-body
= cl_image_tag photo.key, height: 200, width: 400, crop: :fill, class: 'img-fluid'
.card-footer
= link_to "Remove", property_photo_remove_path(@property, photo), \
method: :delete, data: { confirm: 'Are you sure you want to delete this photo?' }, \
class: 'btn btn-light btn-block'
The <%= Rails.env %> folder in storage.yml does all the work. One account, two environments, no extra cost.