Building and deploying a full application with Ruby on Rails. This is a quick library of city sounds that users can upload and view, for listening pleasure during a time of global isolation.
Users can login using social media -- Twitter, Facebook, Google, and Github -- and then create a simple profile. They can upload sounds and contribute to a library.
rails generate scaffold Sounds location:string description:string name:string user:references
rails generate migration UsersSounds
# migration
def change
  create_table :users_sounds do |t|
    t.belongs_to :user, index: true
    t.belongs_to :sound, index: true
    t.timestamps
  end
end
# model
class Sound < ApplicationRecord
  has_one_attached :thumbnail
  has_many_attached :sound_clips
  belongs_to :user
  validates :sound_clips, presence: true, blob: {content_type: [ 'audio/mpeg', 'audio/x-mpeg', 'audio/mp3', 'audio/x-mp3', 'audio/mpeg3', 'audio/x-mpeg3', 'audio/mpg', 'audio/x-mpg', 'audio/x-mpegaudio' ]}
end
# controller
# GET /sounds/new
def new
  @user = current_user
  @sound = @user.sounds.build
end
def create
  @user = current_user
  @sound = @user.sounds.build(sound_params)
  respond_to do |format|
    if @sound.save
      format.html { redirect_to @sound, notice: 'Sound was successfully created.' }
      format.json { render :show, status: :created, location: @sound }
    else
      format.html { render :new }
      format.json { render json: @sound.errors, status: :unprocessable_entity }
    end
  end
end
rails generate model category
rails generate model soundscategories
# migration
def change
  create_table :sounds_categories do |t|
    t.belongs_to :sound, index: true
    t.belongs_to :category, index: true
    t.timestamps
  end
end
# models/sound.rb
has_many :sounds_categories
has_many :categories, through: :sounds_categories
# models/category.rb
has_many :sounds_categories
has_many :sounds, through: :sounds_categories
# models/soundscategory.rb
Create a migration to add optional coords to the sound object so that we can geocode and save easily:
def change
  change_table :sounds do |t|
    t.column :lat, :float, optional: true, :default => "None"
    t.column :lng, :float, optional: true, :default => "None"
  end
end
It's easy to build a tool to serve geojson and display in mapbox. We can create a new controller, and then set a route for it.
yarn add mapbox mapbox-gl leaflet
rails g controller geojson index
class GeojsonController < ApplicationController
  def index
    @sounds = Sound.all
    @geojson = Array.new
    @sounds.each do |sound|
      # To save geocoding usage, check
      # If the record doesn't have coords already:
      if sound.lat == 0.0
        results = Geocoder.search(sound.location)
        sound.lat = results.first.coordinates[0]
        sound.lng = results.first.coordinates[1]
        sound.save
      end
      @geojson << {
        type: 'Feature',
        geometry: {
          type: 'Point',
          coordinates: [sound.lng, sound.lat]
        },
        properties: {
          name: sound.name,
          location: sound.location,
          description: sound.description,
          'marker-color': '#00607d',
          'marker-symbol': 'circle',
          'marker-size': 'large'
        }
      }
    end
    @json = { "type": 'FeatureCollection', "features": @geojson }
    render json: @json
  end
end
Create a new route and map it to the geojson controller
get 'geojson', to: 'geojson#index'