Reviving Old Ideas

Will Carter
7 min readJul 31, 2020

--

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.

http://hikefinder.net

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.

Hikefinder is a hybrid

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.

Hover over the trail head point for details or click on it for full details at https://hikingproject.com
Latitude is like Ladder (goes up and down)

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 api
get '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.

“Populated Places”

This guide and this stack overflow question helped me remember some basic SQL to populate the city model table from another source table.

Along the way, I found that I needed a way to easily test the endpoints of the API. I have used Postman with good success before.

On this project, I tried Insomnia. It worked great. Here is a good blog post comparing the two. I find insomnia is a bit easier to use.

Spaceman or sleep, take your pick.

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.

Active Record Rocks

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.

Nothing like an HTTPARTY!

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!

Slugs!

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.

Data overload!
Geodesics

At a later point during the build of the API back end, I realized that I needed to calculate distance between two latitude/longitude points. This Geodesics gem worked great in multiple places in the app. See it being used in :populate_distance Rakefile method.

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.

Call me Snake…

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. 😃

https://docs.mapbox.com/mapbox-gl-js/api/

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

Change Mouse Cursor Style

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.

https://medium.com/@admatbandara/setting-up-cors-to-my-rails-api-a6184e461a0f

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.

Iconify Design has tons of icons, free to use
Don’t stare at this very long

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.
Need some starter HTML code?

Ever need a basic html shell? Here’s a nice code generator.

JSFiddle

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

--

--