Geo stack is an opiniated Rails stack to build a modern website without the need to deal with the configuration hell.
It was extracted from a project that is providing geo-based data insight for travelers. Thus the PG configuration using geo and search extensions.
Except the geo and search features, this stack is pretty "Rails standard".
- Ruby 3.4.x
- Rails 8.0.x
- Postgresql with Postgis, Pgtrgm, Plpsql and Fuzzystrmatch
- Rgeo suite for geo data manipulation
- Pg search and jaro winkler gems for fuzzy search
- TailwindCSS 4 with DaisyUI 5
- ViewComponent
- Stimulus JS
- Turbo 8
- Active Storage
- Importmap
- Devise
- Minitest
- Capybara
- Rubocop
- Mapbox and Leaflet
- PWA ready
- CI ready with Github Actions
- Production ready using Docker (Dockerfile only)
- Cursor ready with full prompt in /.cursor
- Translation ready for FR and EN
- SEO ready using FriendlyId and sitemap_generator
Soon:
- Solid queue
- Solid cache
- Turbo Native iOS and Android template
- Clone the repository
git clone git@github.com:anthonyamar/geo-stack.git new-app
cd new-app- Rename the Origin remote url, so you can still merge changes in the futur
git remote rename origin geo-stack- Add your origin url (change the git@github.com link for yours)
git remote add origin git@github.com:username/new-app.git- Rename the app
Find and replace all
GeoStackandgeo_stackwith your app name (e.g.NewAppandnew_app)
Run bin/setup to bundle, yarn install, figaro install, prepare db, and restart server.
bin/setupRun your server
bin/devVisit localhost:3000 and Yay π, you're on Rails !
Use the DaisyUI Theme Generator to make your theme, then replace the config in app/assets/tailwind/application.css. You can also tweak heading, paragraph, link and Pagy style in this file.
You can change Tailwind configuration, i.e. colors, spacing, radius, fonts in this file as well. See Tailwind theme doc
Add your FontAwesome kit in application.html.erb to get icon classes.
Fill the config/meta.yml with all the details to enable meta-tags. You can find an example on how to define meta-tags on a per page basis in app/views/static_pages/home.html.erb
Add the URL and collection that you want to have in your sitemap.xml in config/sitemap.rb then run
ruby sitemap.rbYou can include four concerns to get the most of PG extensions. For the example, let's say you have a City model.
Use any or all by adding it in your model:
class City < ApplicationRecord
include GeoCoordinates
include GeoBoundingBox
include Geocoderable
include FuzzySearchable
# ...
endThese will expose methods for geo-search, like nearby?, nearby(), contains?. You'll need to add geo fields to your model.
In your migration:
add_column :cities, :lonlat, :st_point, geographic: true
add_column :cities, :bounding_box_geom, :geometry, geographic: true
add_index :cities, :lonlat, using: :gist
add_index :cities, :bounding_box_geom, using: :gistI advise you to also have the original coordinates as normal float. Not mandatory, but handy sometimes:
add_column :destinations, :original_latitude, :float
add_column :destinations, :original_longitude, :floatWill fetch the result of Geocoder search once, store it in a jsonb field and serves it for you as an OpenStruct when needed. It is meant to increase performances when accessing geo-data without redundancy.
You can force reloading Geocoder config by adding doing city.save(store_geocoder_data: true).
In your migration:
add_column :cities, :geocoder_data, :jsonb, default: {}, null: false
add_index :cities, :geocoder_data, using: :ginThen use, i.e city.geocoder_data.country to access all the Geocoder methods outputing data.
Expose a fuzzy_search_by class methods so you can do something like:
# fuzzy_search_by(attributes, value, threshold: nil, limit: 10)
User.fuzzy_search_by("name", "Kylian", threshold: 0.8, limit: 3)
# => ActiveRecord Collection
# Kylian
# Kyllian
# KyliannIn your migration, index the attributes that you will query:
add_index :cities, :name, using: :gin, opclass: :gin_trgm_ops
add_index :users, :name, using: :gin, opclass: :gin_trgm_ops
add_index :users, :email, using: :gin, opclass: :gin_trgm_opsYou may need to generate a Rails master key for your production environment.
rm config/credentials.yml.enc config/master.key
rails credentials:editThen, fill your RAILS_MASTER_KEY environment variable in production with new one created at config/master.key
Don't forget to set production environment for Rails:
RAILS_ENV=production
In order to push the template in production, you'll need to install a Postgis instance as a database, and add your environment variables like so:
DATABASE_HOST=your-database-host-name-or-url
DATABASE_PORT=5432
DATABASE_USER=postgres
DATABASE_PASSWORD=your-password
DATABASE_NAME=you-database-name
To install Postgis, you have mostly two main options(works for in development environment and production):
- Installing yourself all the packages. You can follow the Rgeo guide on this: Installing Postgis
- Using a Docker image. The official Postgis Docker image only works on x86/amd64 architecture. If you need a Docker image that runs on arm64, you can use imresamu/postgis image.
Troubleshooting Postgis community images on arm64 through Coolify: If you're using Coolify as a PaaS, deploying on arm64 servers, here's the steps:
- Add the imresamu/postgis image in the same project of your app, so they can communicate internaly
- In the General tab, remove the domain, and set the Ports exposes to
5432. - In the advanced tab, uncheck Force Https, and check Consistent Container Names.
- Setup your Environment Variables like so:
POSTGRES_PASSWORD=your-password
POSTGRES_USER=postgres
- In your Ruby on Rails app, set your
DATABASE_HOSTusing the suffix of your database name. I.e., by default, it is something likedocker-image-arandomstringof24chars. YourDATABASE_HOSTwill then bearandomstringof24chars - Don't forget to restart both your database and your app.
Merge changes from the geo-stackremote configured above:
git fetch geo-stack
git fetch geo-stack/mainGeo Stack is released under the MIT License.
Feel free to open issues and PR on this Github repository