Search code examples
javascriptruby-on-railsopenlayers

A nested array is changing to a string of values going from JavaScript to Rails


Using OpenLayers (although I think this is a JS/Rails issue) I draw a box,

var source = new VectorSource();

function addInteraction() {
  var draw = new Draw({
    source: source,
    type: 'Circle',
    geometryFunction: createBox()
  });
  map.addInteraction(draw);
  draw.on('drawend', function(event) {
    var boxCoords = event.feature.getGeometry().getCoordinates()
    console.log(" boxCoords: ", boxCoords);
    document.getElementById('year_snippet_extent').innerHTML = boxCoords;
  });
}

addInteraction();

Console log output (the four corners of the rectangle, but returns to beginning, that's how OpenLayers handles drawing boxes, i.e. it's a polygon):

 boxCoords:  
 [Array(5)]
 0: Array(5)
 0: (2) [977.8497980044467, 710.486212043731]
 1: (2) [1341.059647947079, 710.486212043731]
 2: (2) [1341.059647947079, 754.3238572469668]
 3: (2) [977.8497980044467, 754.3238572469668]
 4: (2) [977.8497980044467, 710.486212043731]

What get's written to year_snippet_extent a field on the edit form: 977.8497980044467,710.486212043731,1341.059647947079,710.486212043731,1341.059647947079,754.3238572469668,977.8497980044467,754.3238572469668,977.8497980044467,710.486212043731

I want to save this to Postgres as an array. Postgres datatype is text [], Rails datatype is the same although my migration was array, add_column :years, :snippet_extent, :text, array:true.

The field in edit is <%= form.input :snippet_extent, label: 'Automatically filled when snippet is drawn' %>

What is reformatting the array? Or should I use a different approach?

I couldn't figure out how to have box_coords saved to snippet_extent directly, so came up with this work around. I could parse what is saved for my purposes, but thought I should be able to make this work right.

Here's what I wrote to get what I think is the correct format (I only need the lower left and upper right corners):

 var minx = Math.round(boxCoords.[0].[0].[0])
 var miny = Math.round(boxCoords.[0].[0].[1])
 var maxx = Math.round(boxCoords.[0].[2].[0])
 var maxy = Math.round(boxCoords.[0].[2].[1])
 var snippetExtent = "{[[" + String(minx) + "," + String(miny) + "],[" + String(maxx) + "," + String(maxy) + "]]}"

Not that hard but I was hoping not necessary. I'm rounding to make it easier to read and the precision is meaningless.


Solution

  • We are using leaflet, but we are doing something quite similar: upon drawing a geometry we show a modal with a form, and we set a hidden text field to contain the geometry.

    We are using postgis, so we immediately store the geojson representation in that hidden field. Not quite sure if that is possible using OpenLayers (pretty sure it is, just not finding it right away). But maybe that is not the easiest format for you? If you are using postgis and activerecord-postgis gem, you can just assign a geojson to a geometry.

    But if not, you will have to parse a geojson yourself (which is not too hard, but definitely a little more complicated).

    So, as mentioned in the comments: JSON is a much better exchange format, always used in API's as both JS and Rails handle it very well.

    So in your JS you could write:

    document.getElementById('year_snippet_extent').innerHTML = JSON.stringify(boxCoords);
    

    and at the rails end you would convert it back to whatever was put it into it as follows:

    box_coords = JSON.parse(params[:year_snippet_extent])