在 Ruby 内调用 PostGIS 函数

Calling PostGIS functions within Ruby

我需要在 Ruby 的 SQL SELECT 子句中执行 PostGIS 函数 st_intersection。目前我正在做原始 SQL 查询:

sql_query = "SELECT id, ST_ASEWKT(ST_INTERSECTION(geometry, ?)) FROM trips WHERE status='active';"
intersections = Trip.execute_sql(sql_query, self[:geometry].to_s)

这种方式的缺点是我收到的结果是文本,我需要从字符串中解析出对象。使用 ActiveRecord 接口进行查询会更好。但是,我在 ActiveRecord 中找不到 运行 PostGIS 函数(例如 st_intersection)的任何解决方案。

activerecord-postgis-adapter 的早期版本 README 使用 gem squeel 展示了一个很好的例子:

my_polygon = get_my_polygon    # Obtain the polygon as an RGeo geometry
MySpatialTable.where{st_intersects(lonlat, my_polygon)}.first

由于这不再是当前 README 的一部分,我想知道是否不推荐这样做,或者是否有更好的选择。

这里有两个问题需要解决

第一个是在 .select 子句中使用 SQL 函数。通常这很容易——您只需使用 AS 为结果命名。这是 ActiveRecord Rails Guide:

中的示例
Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)")

生成的 Order 对象将具有 ordered_datetotal_price 属性。

这给我们带来了第二个问题,即 Rails 没有给我们一个简单的方法来参数化 select(即使用 ? 占位符),所以(据我所知)你需要自己做 sanitize_sql_array:

sql_for_select_intersection = sanitize_sql_array([
  "ST_ASEWKT(ST_INTERSECTION(geometry, ?)) AS intersection",
  geometry,
])

这将 return 一个经过清理的 SQL 片段,如 ST_ASEWKT(ST_INTERSECTION(geometry, '...')),然后您可以使用它来指定 select 中的字段:

Trip.where(status: "active").select(:id, sql_for_select_intersection))

生成的查询将 return 具有 idintersection 属性的 Trip 对象。