{"id":9861,"date":"2018-04-13T16:00:52","date_gmt":"2018-04-13T13:00:52","guid":{"rendered":"https:\/\/railsware.com\/blog\/?p=9861"},"modified":"2021-08-12T13:39:30","modified_gmt":"2021-08-12T10:39:30","slug":"maps-with-react-native-rails-and-postgresql","status":"publish","type":"post","link":"https:\/\/railsware.com\/blog\/maps-with-react-native-rails-and-postgresql\/","title":{"rendered":"Maps with React Native, Rails, and PostgreSQL"},"content":{"rendered":"\n<p class=\"intro-text\">Railsware is a company that deals with numerous tasks and ideas associated with web and mobile development. Our engineers always seek the best solution for optimization of both performance and budgeting. The core vision of Railswarians is a lean approach.<\/p>\n\n\n\n<p>In this overview, we are going to review a development of a feature of geolocation search around user\u2019s current location. React Native was chosen as the framework for building a single application for both the most popular operating systems in the market, namely iOS and Android. The backend part was put into effect through Rails as a web framework and PostgreSQL as a database. Are you ready to learn details and peculiarities of using such an approach for mobile app development? You are welcome to read our experience.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"2400\" height=\"1260\" src=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2018\/04\/Map-Illustration.jpg\" alt=\"Geolocation feature in mobile app\" class=\"wp-image-9869\" srcset=\"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2018\/04\/Map-Illustration.jpg 2400w, https:\/\/railsware.com\/blog\/wp-content\/uploads\/2018\/04\/Map-Illustration-360x189.jpg 360w, https:\/\/railsware.com\/blog\/wp-content\/uploads\/2018\/04\/Map-Illustration-768x403.jpg 768w, https:\/\/railsware.com\/blog\/wp-content\/uploads\/2018\/04\/Map-Illustration-1024x538.jpg 1024w\" sizes=\"auto, (max-width: 2400px) 100vw, 2400px\" \/><\/figure><\/div>\n\n\n\n<p>Let\u2019s begin our publication with the core points related to frontend development. So, using React Native is opening the case.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Track current location<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Setup<\/h3>\n\n\n\n<p>Before enabling geolocation tracking in the application, you should remember that the final product is targeted at both cohorts of mobile device users. We\u2019ll look at Apple first.<br>In order to enable geolocation tracking on iOS, you need to include <code>NSLocationWhenInUseUsageDescription<\/code> key in <code>Info.plist<\/code><\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:plist\">NSLocationWhenInUseUsageDescription\nThe reason why your app want to use location goes gere\n<\/pre>\n\n\n\n<p>A location request access for Android devices is implemented through adding <code>AndroidManifest.xml<\/code> to your application:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:plist\">&nbsp;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">React Native Geolocation API<\/h3>\n\n\n\n<p>The React Native Geolocation API extends the Geolocation web specs and is available globally through the <code>navigator.geolocation<\/code>.<\/p>\n\n\n\n<p>There is the <code>getCurrentPosition<\/code> function that helps access current position:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:es2016\">Geolocation.getCurrentPosition(success, [error], [options]);\n<\/pre>\n\n\n\n<p>Once the latest location information is available, the <code>success<\/code> callback is invoked. However, the we decided to make a small wrapper function that returns <code>Promise<\/code> and hides callbacks logic inside, so that it could be easily chained with other asynchronous actions:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:es2016\">getCurrentPosition() {\n  return new Promise((resolve, reject) =&gt; {\n    navigator.geolocation.getCurrentPosition(\n      ({coords}) =&gt; resolve({\n        latitude: coords.latitude, longitude: coords.longitude\n      }),\n      reject,\n      {enableHighAccuracy: false, timeout: 5000, maximumAge: 1000}\n    )\n  })\n}\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Using react-native-maps<\/h2>\n\n\n\n<p>In order to display maps, the <a href=\"https:\/\/github.com\/react-community\/react-native-maps\" target=\"_blank\" rel=\"nofollow noopener\">react-native-maps package<\/a> was used. Although this solution is imperfect due to multiple bugs and lack of documentation to cope with them, it provides a set of features we need to display information on maps. Moreover, it works on both iOS and Android at the same time.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Render map<\/h3>\n\n\n\n<p>We used a default setup where both mobile operating systems render their own maps: Apple Maps on iOS and Google Maps on Android.<\/p>\n\n\n\n<p>The <code>MapView<\/code> component is built to show maps on the device. It provides a react-like API for declaratively controlling features. All features on maps including Markers, Polygons, etc. should be specified as children of this component. Have a look at the following example use:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:es2016\">  \n\n<\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li><code>showsUserLocation<\/code> property is used to show natively user location.<\/li><li><code>initialRegion<\/code> displays the initial region on the map.<\/li><li><code>style<\/code> is basically set to be positioned absolute and fill the entire screen.<\/li><\/ul>\n\n\n\n<p>A complete API description of <code>MapView<\/code> component can be found in the following <a href=\"https:\/\/github.com\/react-community\/react-native-maps\/blob\/master\/docs\/mapview.md\" target=\"_blank\" rel=\"nofollow noopener\">documentation<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Render Markers on the map<\/h3>\n\n\n\n<p>The <code>PlacesMarkers<\/code> is a React Native component implemented in our application to render place markers on the map. Its functionality is as:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:es2016\">render() {\n  const {places} = this.props\n\n  if (!places.length) return null\n\n  return (\n    \n      {\n       places.map(place =&gt; {\n          return (\n            \n          )\n        })\n      }\n    \n  )\n}\n<\/pre>\n\n\n\n<p>The list of places to render on the map pass as props to this component (it comes from the redux state but we skipped this part here).<\/p>\n\n\n\n<p>Another component provided by react-native-maps is called <code>MapView.Marker<\/code>. It renders markers on the map and provides a set of features described in the <a href=\"https:\/\/github.com\/react-community\/react-native-maps\/blob\/master\/docs\/marker.md\" target=\"_blank\" rel=\"nofollow noopener\">documentation<\/a>. Of all them, we used the following ones:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>coordinate<\/code> &#8211; to place marker to the proper position;<\/li><li><code>key<\/code> &#8211; since we render a list of items, a unique <code>key<\/code> value is required by React Native;<\/li><li><code>image<\/code> &#8211; to specify a contone image to be shown as a marker.<\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Issues<\/h3>\n\n\n\n<p>As it was mentioned above, there are a lot of issues documented in the repo. Some of them were reported more than one year ago but still persist. One such <a href=\"https:\/\/github.com\/react-community\/react-native-maps\/issues\/678\" target=\"_blank\" rel=\"nofollow noopener\">issue<\/a> is the display of distant markers in the top left corner of the maps. We exhausted multiple approaches to fix it and eventually solved with a funny hack: we simply moved the entire map 20 pixels up (marker height), so that these markers always remain out of the visible area for user :)<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:es2016\">map: {\n  ...StyleSheet.absoluteFillObject,\n  top: -20 \/\/ hack required for https:\/\/github.com\/airbnb\/react-native-maps\/issues\/678\n}\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Backend<\/h2>\n\n\n\n<p>That\u2019s it for the frontend. Let\u2019s take a look at the backend now. We\u2019ll put aside React Native and focus on other tools we used. Rails was chosen as a web framework to build API for mobile applications and PostgreSQL \u2013 as a database. The latter draws our special attention.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Using PostGIS to search within an area<\/h3>\n\n\n\n<p>PostGIS that is a spatial database extender for PostgreSQL database was used to search places within an area. The extender adds support for geographic objects enabling the user to run location queries in SQL.<\/p>\n\n\n\n<p>You should use the following migration to enable PostGIS extension:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:ruby\">class EnablePostgis &lt; ActiveRecord::Migration[5.1]\n  def change\n    enable_extension :postgis\n  end\nend\n<\/pre>\n\n\n\n<p>All our places have <code>latitude<\/code> and <code>longitude<\/code> fields containing coordinates on the map. Hence, our <code>ActiveRecord<\/code> model scope looks as follows:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:ruby\">class Place &lt; ApplicationRecord\n  scope :within, -&gt; (latitude, longitude, distance_in_meters = 1) {\n    where(\n      format(%{\n          ST_DWithin(\n            ST_GeographyFromText(\n              'SRID=4326;POINT(' || places.longitude || ' ' || places.latitude || ')'\n            ),\n            ST_GeographyFromText('SRID=4326;POINT(%f %f)'),\n            %d\n          )\n        }, longitude, latitude, distance_in_meters)\n    )\n  }\nend\n<\/pre>\n\n\n\n<p>PostGIS provides the <code>ST_DWithin<\/code> spatial function, which was used to check whether places are located within the specified distance from the current user location passed to the scope.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>The above-described issues should be the bullet points to consider in projects dealing with embedding a geolocation search feature. Certainly, it refers to using React Native as a frontend technology, and Rails plus PostgreSQL as tools to build the backend part. The mentioned technologies proved their efficiency and practicability for such type projects.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this overview, we are going to review a development of a feature of geolocation search around user\u2019s current location.<\/p>\n","protected":false},"author":44,"featured_media":9868,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3],"tags":[],"coauthors":["Olexander Paladiy"],"class_list":["post-9861","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development"],"acf":[],"aioseo_notices":[],"categories_data":[{"name":"Engineering","link":"https:\/\/railsware.com\/blog?category=development"}],"post_thumbnails":"https:\/\/railsware.com\/blog\/wp-content\/uploads\/2018\/04\/Map-Illustration.jpg","amp_enabled":true,"_links":{"self":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/9861","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/users\/44"}],"replies":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/comments?post=9861"}],"version-history":[{"count":11,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/9861\/revisions"}],"predecessor-version":[{"id":13972,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/posts\/9861\/revisions\/13972"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media\/9868"}],"wp:attachment":[{"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/media?parent=9861"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/categories?post=9861"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/tags?post=9861"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/railsware.com\/blog\/wp-json\/wp\/v2\/coauthors?post=9861"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}