保存前如何在rails中使用ST_GeoHash和ST_MakePoint postgis函数?
How to use ST_GeoHash and ST_MakePoint postgis functions in rails before save?
如何在 rails postgis 点中构建,然后在将响应发送给客户端之前进行 geohash 并将它们保存到数据库中?我想通过 ST_MakePoint
和 ST_GeoHash
函数实现,我更愿意避免执行 SQL 并通过 [0]["st_makepoint"]
提取数据,如果可能如何将此函数插入到插入所有属性时自动执行它们?我已经安装了 squeel gem,也许我可以将这个函数合并到查询中吗?
我当前的rails代码:
before_save :set_geopoint
def set_geopoint
#attributes -> {"latitude" => 51.90,"longitude" => 16.42,"geopoint" => nil}
#self.geopoint = "ST_MakePoint(#{latitude}, #{longitude})")" #not working
#self.geopoint = ActiveRecord::Base.connection.execute("SELECT ST_MakePoint(#{latitude}, #{longitude})")[0]["st_makepoint"]
#self.geohash = "ST_GeoHash(#{self.geopoint})"
#self.geohash = ActiveRecord::Base.connection.execute("SELECT ST_GeoHash(ST_SetSRID(#{self.geopoint},4326),5);").first["st_geohash"]
end
我在触发函数之前通过 SQL 做到了,但我仍在寻找 rails 方法。
CREATE FUNCTION geopoint_trigger() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO posts( geopoint ) VALUES( ST_GeomFromText('POINT(' || NEW.latitude || ' ' || NEW.longitude || ')') );
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';
要生成可以保存在支持 postgis 的数据库中的点,您需要使用工厂生成该点。你在这里做什么:
self.geopoint = "ST_MakePoint(#{latitude}, #{longitude})")" #not working
只是将 self.geopoint
设置为一个字符串并尝试保存它。由于您的数据库地理点字段(我假设)设置为接受一个点,因此它失败了。
我建议您使用 rgeo gem 将地理工厂添加到您的模型中。将其添加到您的 Gemfile
.
您需要确保在迁移中使用点作为列类型,如下所示:
t.point :geopoint, geographic: true
在您的 Post
模型中,您需要像这样指定一个工厂:
RGEO_FACTORY = RGeo::Geographic.spherical_factory(srid: 4326)
并且您还需要告诉 rgeo 在您的 geopoint
列上使用哪个工厂。
set_rgeo_factory_for_column :geopoint, RGEO_FACTORY
现在在您的 before_save
中,只需执行以下操作:
self.geopoint = RGEO_FACTORY.point(latitude, longitude)
它应该可以工作...
编辑
例如,如果您想在 Rails 模型中使用 Postgis 函数来获取 GeoHash
,那么您可以这样做:
post_geohash = Post.select("ST_GeoHash(geopoint) as geohash").where(id: some_post_id).geohash
您还可以创建一个在您的 Post 模型上执行此操作的实例方法:
def geohash
Post.select("ST_GeoHash(geopoint) as geohash").where(id: id).geohash
end
不确定这是否有效,因为它未经测试,但你明白了。
如何在 rails postgis 点中构建,然后在将响应发送给客户端之前进行 geohash 并将它们保存到数据库中?我想通过 ST_MakePoint
和 ST_GeoHash
函数实现,我更愿意避免执行 SQL 并通过 [0]["st_makepoint"]
提取数据,如果可能如何将此函数插入到插入所有属性时自动执行它们?我已经安装了 squeel gem,也许我可以将这个函数合并到查询中吗?
我当前的rails代码:
before_save :set_geopoint
def set_geopoint
#attributes -> {"latitude" => 51.90,"longitude" => 16.42,"geopoint" => nil}
#self.geopoint = "ST_MakePoint(#{latitude}, #{longitude})")" #not working
#self.geopoint = ActiveRecord::Base.connection.execute("SELECT ST_MakePoint(#{latitude}, #{longitude})")[0]["st_makepoint"]
#self.geohash = "ST_GeoHash(#{self.geopoint})"
#self.geohash = ActiveRecord::Base.connection.execute("SELECT ST_GeoHash(ST_SetSRID(#{self.geopoint},4326),5);").first["st_geohash"]
end
我在触发函数之前通过 SQL 做到了,但我仍在寻找 rails 方法。
CREATE FUNCTION geopoint_trigger() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO posts( geopoint ) VALUES( ST_GeomFromText('POINT(' || NEW.latitude || ' ' || NEW.longitude || ')') );
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';
要生成可以保存在支持 postgis 的数据库中的点,您需要使用工厂生成该点。你在这里做什么:
self.geopoint = "ST_MakePoint(#{latitude}, #{longitude})")" #not working
只是将 self.geopoint
设置为一个字符串并尝试保存它。由于您的数据库地理点字段(我假设)设置为接受一个点,因此它失败了。
我建议您使用 rgeo gem 将地理工厂添加到您的模型中。将其添加到您的 Gemfile
.
您需要确保在迁移中使用点作为列类型,如下所示:
t.point :geopoint, geographic: true
在您的 Post
模型中,您需要像这样指定一个工厂:
RGEO_FACTORY = RGeo::Geographic.spherical_factory(srid: 4326)
并且您还需要告诉 rgeo 在您的 geopoint
列上使用哪个工厂。
set_rgeo_factory_for_column :geopoint, RGEO_FACTORY
现在在您的 before_save
中,只需执行以下操作:
self.geopoint = RGEO_FACTORY.point(latitude, longitude)
它应该可以工作...
编辑
例如,如果您想在 Rails 模型中使用 Postgis 函数来获取 GeoHash
,那么您可以这样做:
post_geohash = Post.select("ST_GeoHash(geopoint) as geohash").where(id: some_post_id).geohash
您还可以创建一个在您的 Post 模型上执行此操作的实例方法:
def geohash
Post.select("ST_GeoHash(geopoint) as geohash").where(id: id).geohash
end
不确定这是否有效,因为它未经测试,但你明白了。