Skip to content

Conversation

@nimmolo
Copy link
Contributor

@nimmolo nimmolo commented Jan 2, 2026

Fixes the broken "Get Elevations" button on the Location form - switches from Google Elevation API (which has referrer restrictions) to Open-Elevation API. Elevations auto-populate after geocoding a location. Fixes #3690.

Takes GoogleElevationAPI off our bill completely. Pretty nifty coding from Claude, too. Very minimal changes to Stimulus; the call comes from Ruby.

Manual Test

There's a new system test for the elevation fields getting populated from OpenElevation, but manual test welcome. Pick a place to geocode in the /locations/new form, and it should get its bounds and elevation min/max populated.

Changes

  • Calls Open-Elevation API via a backend proxy, instead of directly from JS. This may guard against referrer restrictions in the future.
  • Creates /geo namespace - new internal API for geographic services
  • Adds CorsHeaders concern - consolidated duplicate CORS code between API2 and Geo controllers

New files:

  • app/controllers/concerns/cors_headers.rb - CORS concern
  • app/controllers/geo/base_controller.rb - Base geo controller
  • app/controllers/geo/elevations_controller.rb - Elevation proxy
  • test/controllers/geo/elevations_controller_test.rb - Tests

Modified files:

  • app/controllers/api2_controller.rb - Uses CORS concern
  • app/javascript/controllers/geocode_controller.js - Uses /geo/elevation
  • app/javascript/controllers/map_controller.js - Input fallback for sampleElevationPoints
  • config/routes.rb - Added /geo/elevation route
  • test/system/location_form_system_test.rb - Added (skipped) elevation test
  • test/test_helper.rb - Allow Open-Elevation & Google APIs

Takes GoogleElevationAPI off our bill completely.

Pretty nifty coding from Claude, too. Very minimal changes to Stimulus; the call comes from Ruby.

  New files:
  - app/controllers/concerns/cors_headers.rb - CORS concern
  - app/controllers/geo/base_controller.rb - Base geo controller
  - app/controllers/geo/elevations_controller.rb - Elevation proxy
  - test/controllers/geo/elevations_controller_test.rb - Tests

  Modified files:
  - app/controllers/api2_controller.rb - Uses CORS concern
  - app/javascript/controllers/geocode_controller.js - Uses /geo/elevation
  - app/javascript/controllers/map_controller.js - Input fallback for sampleElevationPoints
  - config/routes.rb - Added /geo/elevation route
  - test/system/location_form_system_test.rb - Added (skipped) elevation test
  - test/test_helper.rb - Allow Open-Elevation & Google APIs
@nimmolo nimmolo requested review from JoeCohen and mo-nathan January 2, 2026 08:29
@nimmolo nimmolo marked this pull request as ready for review January 2, 2026 08:33
@coveralls
Copy link
Collaborator

coveralls commented Jan 2, 2026

Coverage Status

coverage: 95.372%. remained the same
when pulling 5fe6a47 on nimmo-open-elevation
into 5e79c28 on main.

Copy link
Member

@mo-nathan mo-nathan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this seems to be working great! However, I noticed that the "Get Elevations" button is now seems to always be disabled (or I don't know how to enable it). If it is always disabled, then we should get rid of it. Even if it's only very often disabled, then I think it would be better to hide it rather than disable it.

@nimmolo
Copy link
Contributor Author

nimmolo commented Jan 2, 2026

I found the source of our Google Elevation API billing issue.

The problem: bounds_changed and position_changed fire on every pixel during drag/resize. 
This could send dozens of requests per second!

Copy link
Member

@JoeCohen JoeCohen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job. Code works as intended.

~~ But how reliable/accurate is Open-Elevation?~~
How are we determining min/max?
AFAIK both Open-Elevation and Google can return elevation only for points.

So min/max for boxes can be way off.
I tried this:

The highest point in Burkina Faso is Mount Tenakourou, at 747 m.
https://www.cia.gov/the-world-factbook/countries/burkina-faso/
Google Maps terrain view

So min/max using Open-Elevation was off by > 1,300 feet.
For Mount Hood National Forest, it gave me 17/1096. The high point there is Mount Hood, 3,429m. So we're off by 1.45 miles.

@nimmolo
Copy link
Contributor Author

nimmolo commented Jan 3, 2026

@JoeCohen Great question and I appreciate your thorough documentation of the issue.

Claude says:
None of the free APIs return min/max directly for a bounding box.

Better sampling with Open-Elevation

Since you're already using https://open-elevation.com/ (1,000 free requests/month), you could increase the sample density:

Grid Points Coverage
3×3 9 Basic
5×5 25 Moderate
7×7 49 Good
9×9 81 Very good

Open-Elevation accepts multiple points per request, so a 7×7 grid is still just 1 API call.

Recommendation: A 5×5 or 7×7 grid would be a good balance - much better coverage for mountainous terrain while staying within a single request. Want me to implement that?

I said: How about 9x9!

@nimmolo
Copy link
Contributor Author

nimmolo commented Jan 3, 2026

Switched to 9x9 and getting better elevations.

Mount Hood National Forest now gives 2073/163m, which is only off by a mile ;)
I'm not sure the peaks matter that much, though, honestly. We're not an almanac, and i doubt anyone gathering lichen samples at 10,000 feet is ignorant of the elevations they're seeking.

"Still, she persevered." She proposed a test of increasing grid density, and here's what she got.

⏺ Results for Mt. Hood area:

Grid Points High (m) Low (m) Range (m)
9×9 81 2,073 163 1,910
12×12 144 2,191 279 1,912
15×15 225 2,266 277 1,989
18×18 324 2,256 187 2,069
21×21 441 2,703 202 2,501

Mt. Hood's actual peak is 3,429m - so even 21×21 (441 points) only captured 79% of the true elevation. But 21×21 gets us 630m higher than 9×9. The higher density clearly helps for mountainous terrain.

The lows are also interesting: 9x9 seems closest to the true low elevation.

That's the classic grid sampling problem. The 9×9 grid happened to land on a lower point that the denser grids missed entirely. The "true" low for that area (which includes parts of the Columbia River valley) could be close to sea level.

What grid size do you want to use? 12×12 (144 points) might be a good balance - still a single API call, reasonable accuracy. Or go bigger if the API can handle it.


Re: button, modified Get Elevations button to be hidden instead of disabled after fetch. Claude says:

⏺ The elevations are auto-fetched when:

  1. A place name is geocoded
  2. The rectangle is dragged/resized on the map
  3. A location is selected from the autocompleter

The "Get Elevations" button is only needed for the edge case where someone manually types NSEW coordinates directly into the input fields without any map/geocode interaction.

So the current behavior (button visible initially, hidden after fetch) should work well - it's there if you need it for manual entry, and disappears once elevations are populated.

@nimmolo
Copy link
Contributor Author

nimmolo commented Jan 3, 2026

Pursuant to the conversation on Slack, i will shelve this PR.

@nimmolo nimmolo marked this pull request as draft January 3, 2026 21:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Location form: "Get elevations" broken

5 participants