Here I am building the website for our Kinderladen Kila Hildegarten.
The website is currently reachable through https://kila-hildegarten.herokuapp.com/
The main website is: https://kila-hildegarten.de
Using Cloudflare to securely connect with the domain provider required redirecting from HTTP to HTTPS. This does not work correctly with Devise since the request header is not changed from HTTP to HTTPS. Following this Rails issue #22965, I implemented the recommendation by TonyTonyJan.
Turbolinks are disabled for links in the Materialize sidenav bar. If they are enabled, the links will not work after first-time triggering.
- Security policies are managed via the SecureHeaders gem. Policies are controlled through
config/initializers/secure_headers.rb. - The app is hosted on Heroku.
- There is also an API connection to Webling.
- Redis (Heroku Redis) is used to cache Webling photos for previews.
- Photos are stored on Dropbox, using a custom Dropbox connection gem updated for current compatibility.
This repository contains the Ruby on Rails application for the Kinderladen Kila Hildegarten website. It serves both the public website and an internal admin integration with Webling.
π Production: https://kila-hildegarten.de π§ͺ Staging (Heroku): https://kila-hildegarten.herokuapp.com
The app provides a CMS-like interface. It allows admins to log in and update website content and photos stored on Dropbox.
For our Webling Kila management software, we use a secured page /webling_photos for managing photo previews, content pages, and member information synced from Webling.
Only admins with the correct access token can access this page.
It uses Cloudinary for asset storage and Redis caching for photo previews. Cloudinary is configured as a Heroku add-on.
The stack is intentionally lightweight and optimized for hosting on Heroku with Cloudflare as CDN and SSL proxy.
- Ruby on Rails (7.x)
- Ruby version: specify your current version (e.g.
3.2.3) - Database: PostgreSQL (Heroku managed)
- Cache: Redis (Heroku Redis)
- Website Hosting: Heroku
- SSL: via Cloudflare
- Domain: managed via
one.com
- Assets (images, CSS, JS) are served via the Rails Asset Pipeline (Sprockets).
- On deploy, assets are precompiled with fingerprints (e.g.
placeholder-<hash>.png). - The placeholder image lives in:
app/assets/images/placeholder.png
Example usage:
= image_tag('placeholder.png', onerror: "this.src='#{image_path('placeholder.png')}'")If assets 404 in production:
heroku run rails assets:clobber
heroku run rails assets:precompile- Dropbox is used to store original photo files for the website (via a custom Dropbox connection gem).
- Cloudinary is used by ActiveStorage for image transformations (
resize_to_limit, etc.). Images are cached and served lazily to improve load times.
The app uses the SecureHeaders gem.
Configuration is defined in config/initializers/secure_headers.rb.
Key setting:
img_src: %w('self' data: blob: https://*.dropboxusercontent.com https://res.cloudinary.com)This allows images to be loaded from:
- Local assets (
'self') - Inline data URIs (
data:) - ActiveStorage blob URLs (
blob:) - Dropbox and Cloudinary
Integrates with the Webling API to fetch folders, files, and member information.
API results are cached in Redis to reduce requests.
Webling file objects are wrapped via WeblingFile ActiveRecord models.
The /webling_photos page is embedded into the third-party Webling app via iframe.
Redis is used for caching photo previews and metadata. Cached photos are refreshed periodically when Webling data changes.
Uses Devise for user authentication. Because Cloudflare acts as an HTTPS proxy, Devise must recognize the original protocol correctly. Configuration follows Rails issue #22965 (credit: TonyTonyJan).
Built with MaterializeCSS. Turbolinks are disabled for sidenav links to prevent reinitialization issues.
Example:
= link_to 'Gallery', photos_path, data: { turbolinks: false }The Kila Hildegarten app integrates several external services to deliver optimized photo content and a secure web experience.
ββββββββββββββββββββββββ
β Webling Platform β
β (member + file API) β
ββββββββββββ¬ββββββββββββ
β JSON API calls
β (authenticated via token)
βΌ
βββββββββββββββββββββββββββββ
β Rails Application β
β (Heroku) β
β β
β β’ Fetches data from Webling
β β’ Stores metadata in PostgreSQL
β β’ Caches previews in Redis
β β’ Uses SecureHeaders for CSP
β β’ Serves assets via Asset Pipeline
βββββββββββββ¬βββββββββββββββββ
β
ActiveStorage β Cache Layer
(with Cloudinary adapter) β (Redis on Heroku)
ββββββββββββββββββββββββββ β ββββββββββββββββββββββ
β Cloudinary CDN ββββββββΌβββββββ Redis β
β Stores image variants β β Cached previews β
ββββββββββββββββββββββββββ ββββββββββββββββββββββ
β
β
βΌ
ββββββββββββββββββββββββββββ
β Cloudflare Proxy/CDN β
β β’ HTTPS + Caching layer β
β β’ Enforces SSL redirect β
ββββββββββββ¬ββββββββββββββββ
β
β HTTPS / HTTP2
βΌ
ββββββββββββββββββββββββββββ
β Browser β
β (Parent or Member view) β
β β
β - Loads Materialize CSS β
β - Lazy-loads images β
β - Falls back to β
β `placeholder.png` if β
β image fails to load β
ββββββββββββββββββββββββββββ
- Webling β Rails: Fetch photo metadata and folder info from the Webling API.
- Rails β Dropbox: Retrieve original photo files via Dropbox gem.
- Rails β Cloudinary: Store and serve image variants (resized previews).
- Rails β Redis: Cache photo metadata and Cloudinary URLs.
- Rails β Cloudflare β Browser: Serve all content securely via Cloudflare.
- Browser: MaterializeCSS frontend with lazy loading and placeholder fallback.
- SecureHeaders with custom CSP allows Dropbox and Cloudinary image sources.
- Resilient image loading using lazy
data-srcand fallback placeholders. - HTTPS enforcement via Cloudflare and trusted proxy config.
- Lightweight integration β Webling acts as backend data source.
bundle install
bin/rails db:setup
bin/rails sRun in production mode locally:
RAILS_ENV=production bin/rails assets:precompile
bin/rails s -e productionDeploy to Heroku:
git push heroku main
heroku run rails db:migrateRebuild all assets:
heroku run rails assets:clobber
heroku run rails assets:precompile| Task | Command |
|---|---|
| Clear cache | heroku redis:cli --flushall |
| Rebuild assets | heroku run rails assets:clobber && heroku run rails assets:precompile |
| Restart dynos | heroku restart |
| Run database migrations | heroku run rails db:migrate |
| Open Rails console | heroku run rails c |
| Check logs | heroku logs --tail |
| Issue | Description | Solution |
|---|---|---|
| Devise login redirects incorrectly (HTTP/HTTPS) | Cloudflare proxy affects request scheme | Use config.force_ssl = true and trust proxy headers |
| Placeholder 404 | Asset pipeline not refreshed | Run rails assets:clobber && rails assets:precompile |
| Cloudinary images blocked | CSP restriction | Add https://res.cloudinary.com to img_src in secure_headers.rb |
Developed by Theresa Mannschatz for Kinderladen Kila Hildegarten e.V. https://theresamannschatz.design Β© 2025 β All rights reserved.