Reviving Old Ideas
The following is a collection of guides, tutorials, stackoverflow questions and docs that were useful when building Hikefinder, my forth portfolio project in the Flatiron School software engineering program. Hikefinder allows users to search from a collection of over 30,000 hiking trails across the entire USA. Users can easily search by city name or by specific latitude and longitude coordinate. The source of the trail data for the app is the Hiking Project API.
HikeFinder is a revival of sorts. It covers the same territory as my first Flatiron project, The Hiking Project CLI. This version opens the potential audience up quite a bit as it is now accessible on the web.
The app has front end and a back end. The back end is based on Ruby on Rails and Active Record. It sends and receives hiking trail data to and from a JavaScript front end, which is essentially a a searchable map. This guide, as well as this blog post were helpful to understand how to set up a JSON API with a Rails web app.
The following are a series of generate statements that auto-magically conger a back end very quickly. Here are the magic words that I used:
rails generate scaffold Trail hiking_project_id:integer name:string trail_type:string summary:string difficulty:string stars:float starVotes:integer location:string url:string imgSqSmall:string imgSmall:string imgSmallMed:string imgMedium:string length:float ascent:integer descent:integer high:integer low:integer longitude:float latitude:float conditionStatus:string conditionDetails:string conditionDate:date features:string overview:string description:stringrails generate scaffold City name:string state:string country:string latitude:float longitude:float timezone:string population:integerails generate scaffold CitiesTrail city_id:integer trail_id:integer
Poof! Just from these few command line statements, a useful back end is generated, trail and city CRUD endpoints ready to go.
As mentioned earlier, the the ultimate source of the data for Hikefinder is the Hiking Project API.
The back end API, which drives the HikeFinder front end directly, is a hybrid. If a user searches for trails with the target icon, the results come from the Hiking Project API. But, if a city name search is used, the trail data comes from a local database containing city and trail models.
Here is an example call to the Hiking Project API along with the the trail data that is returned for a specific latitude/longitude coordinate.
From this returned data, points representing hiking trail heads appear on the map. For example, here are some hiking trails found for Seattle, WA.
An early obstacle to overcome with the back end was that I needed to have the endpoint for location based trails to contain the latitude and longitude coordinates. For example:
http://hikefinder.net:3000/trails/41.95/-87.63/5/15
Notice that these values contain a period(.), which needs to be recognized and handled in order for the endpoint to work. I used the technique described in this blog post, this stack overflow question, and this one to add the following code to routes.rb. This allowed for the decimal based url to work correctly.
# this goes to the apiget 'trails/:latitude/:longitude/:max_distance/:max_results', to: 'trails#for_coords', constraints: {
:latitude => /[^\/]+/,
:longitude => /[^\/]+/,
:max_distance => /[^\/]+/,
:max_results => /[^\/]+/,
}
For the app’s city data, which drives the cities that appear in the autocomplete search box, I started with this geographic dataset of places in the USA. This data is in turn is based on U. S. Census data.
This guide and this stack overflow question helped me remember some basic SQL to populate the city model table from another source table.
This stack overflow question was useful when I was figuring out my data population rake task that calls the Hiking Project API for each of the top ~6000 cities by population in the USA. See :populate_trails_for_cities task in the Rakefile for more details on how I populated trail data based on city.
Find or create by is a very powerful method in Active Record. It let’s you instantiate an object from the database if it exists, otherwise it creates a new one.
Because I am keeping track of the hiking_project_id unique id the local database, I refresh trail data with with the latest from the Hiking Project when a trail from an API based query matches one that already exists in the local db. Find or create by hiking_project_id makes this refresh of local trail data very easy to do.
I used the httparty gem to make the API calls to the Hiking Project when the user queries the map by a latitude/longitude point. Simple and easy to use.
I needed city slugs (oh my!), so that a url like the following would work:
http://hikefinder.net:3000/cities/new-york/ny/trails
(notice the lowercase and dash in new-york)
I followed the guidance in this blog post regarding populating city slugs.
Check out :populate_city_slugs rake task in RakeFile for more detail on how to create your own slugs. Ew!
As mentioned earlier, Hikefinder has more than 30,000 trails, 6000 cities and 40,000 citiesTrails associations. The rake db:seed method began throwing errors related to the file size of seed.rb growing too large.
After some experimentation, I figured out that if you run the the rake task, :populate_db, in RakeFile, it will populate the tables even with very large seed files instead of using rake db:seed. This blog post and this stack overflow question were helpful to work through these large dataset issues and write the :populate_db rake task.
Ever need some fresh filler or lorem ipsum text? Here’s a good source. For example, how about some Zombie Ipsum?
Zombie ipsum reversus ab viral inferno, nam rick grimes malum cerebro. De carne lumbering animata corpora quaeritis. Summus brains sit, morbo vel maleficia? De apocalypsi gorger omero undead survivor dictum mauris. Hi mindless mortuis soulless creaturas, imo evil stalking monstra adventus resi dentevil.
This resource and this sample explain how to send a PATCH request using JavaScript fetch. Such a request is used when the user clicks on a trail detail. The app accumulates a click count for each trail in order to drive a “most popular trails listing” if when activity on Hikefinder goes viral. 😃
I used a favorite, very capable Mapbox GL JS API to drive the map functionality of the app. Examples listed below helped to drive the code for various features of the front end. Here are some key Mapbox documentation resources.
Show mouse position on hover with pixel and latitude and longitude coordinates
Plot latitude and longitude based data points on a map
Show a different base map (like a satellite view) without losing data currently displaying on the map. More details can be found here.
Need to label your points? Here is a good example.
After adding the Rack-Cors gem described in this blog post and adding the code below to application.rb, CORS related troubles evaporated.
#application.rbconfig.middleware.insert_before 0, Rack::Cors doallow do
origins ‘*’
resource ‘*’, :headers => :any, :methods => [:get, :post, :patch, :options]
end
end
Iconify Design is slick source of many icons for your app. I used it for the target icon and the pointer icon. They seem to have thousands of SVG icons, free to use.
Here is the source for the loading spinner functionality. Easy.
This stack overflow question describes a nice way to run a rails server in the background. Easy.
rails s -d ## With default Port.
rails s -p 8888 -d ## With Custom port.
Ever need a basic html shell? Here’s a nice code generator.
The autocomplete that being used for the City, State search dropdown is based on this JSFiddle.
Here is a list of project deliverables for the back end and front end (specific code line numbers are referenced for each deliverable).
Here is a overview video of the HikeFinder app: https://www.youtube.com/watch?v=2fK7-zI9Kzc