【问题标题】:How do I stop rails from escaping values in SQL for a particular column?如何阻止 rails 在 SQL 中为特定列转义值?
【发布时间】:2009-08-27 02:01:29
【问题描述】:

我正在尝试手动管理 rails 模型中的一些几何(空间)列。

更新几何列时,我在 rails 中执行此操作:

self.geom="POINTFROMTEXT('POINT(#{lat},#{lng})')"

这是我希望在 SQL 更新中的值,以便由数据库评估。然而,当它通过主动记录魔法时,它变成了:

INSERT INTO `places` (..., `geom`) VALUES(...,'POINTFROMTEXT(\'POINT(52.2531519,20.9778386)\')')

换句话说,引号被转义了。这对其他列很好,因为它可以防止 sql 注入,但不适用于此。这些值保证是浮点数,我希望更新看起来像:

INSERT INTO `places` (..., `geom`) VALUES(...,'POINTFROMTEXT('POINT(52.2531519,20.9778386)')')

那么有没有办法关闭特定列的转义?或者有更好的方法来做到这一点?

(我尝试过使用 GeoRuby+空间适配器,空间适配器对我来说似乎太麻烦了,而且我不需要所有功能 - 因此尝试直接使用)。

【问题讨论】:

  • 我不太确定这里有什么问题。如果这些引号没有被转义,你会因为不正确的引号引起 SQL 错误。如果您检索保存的数据,则不应出现转义字符
  • 关于错误关闭的引号的好点。但是,我从不需要检索这个值——它只用于空间索引。我试图得到这样的等价物: UPDATE places set geom=POINTFROMTEXT('POINT(52,253,20.977')
  • 另一种看待它的方式是,每当更新 lat、lng 列时,我都想更新 geom。在我的 geom 迁移中,我在添加列后执行以下操作:执行“UPDATE #{table} set geom=POINTFROMTEXT(CONCAT('POINT(',lat,'',lng,')'))”。我想在 lat 或 lng 更改时触发类似的更新 - 无论是在 DB 触发器中还是通过 rails。我目前正在使用 before_save 回调,这导致了上述问题。而且我不知道如何在迁移中定义数据库触发器。

标签: mysql ruby-on-rails geometry escaping geospatial


【解决方案1】:

Rails Spatial Adapter 应该完全满足您的需求。虽然,在我找到 GeoRuby & Spatial Adapter 之前,我是这样做的:

  • 在模型上有两个字段:一个文本字段和一个真实几何字段
  • after_save 钩子上,我运行了这样的东西:

    connection.execute "update mytable set geom_column=#{text_column} where id=#{id}"

但上面的解决方案只是一个 hack,这还有其他问题:如果列允许 NULL 值,我无法创建空间索引,MySQL 不允许我在几何列上设置默认值,如果几何列没有设置值,save 方法将失败。

所以我会尝试使用 GeoRuby 和 Spatial Adapter,或者重用它的一些代码(就我而言,我正在考虑从 Spatial Adapter 代码中仅提取支持 GIS 的 MysqlAdapter#quote 方法)。

【讨论】:

  • 谢谢,这就是我最终要做的。我发现它对 rails 版本有点挑剔(例如,当我尝试时似乎在最新版本上不起作用,但在 2.3.2 上还可以),但是当它起作用时,它就成功了。
  • Spatial Adapter 代码上的 rails-version 检查欺骗的数量是我选择只复制 MysqlAdapter.quote 代码而不是尝试使用整个模块的原因。 :)
【解决方案2】:
  1. 您可以使用 after_save 方法,通过直接 SQL UPDATE 调用来编写它们。烦人,但应该可以。

  2. 您应该能够使用“执行”方法在数据库迁移中创建触发器...但我从未尝试过。

  3. 深入研究 ActiveRecord 的计算功能:max/min/avg 等。不确定这是否比 after_save 中的直接 SQL 调用节省了很多。请参阅计算.rb。

  4. 您可以修补引用属性的函数(查找 POINTFROMTEXT,然后跳过引用)。这很容易找到,因为所有方法都以引号开头。从 ActiveRecord::Base #quote_value 开始。

【讨论】:

  • 谢谢。我实际上已经尝试过触发方法,但它似乎不起作用 - mysql 中的某些东西在触发器被调用之前反弹了更新。我现在重新访问了空间适配器,它似乎可以工作,但对 rails 版本很敏感(也许还有 mysql 版本 - 需要做更多测试)
  • 哦,after_save 可能无法开箱即用,因为 rails 首先尝试将 NULL 写入 geom,但由于 geom 上存在非空约束而失败。所以需要以某种方式阻止rails首先更新该属性本身。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-12
  • 2014-11-02
  • 2015-08-02
  • 1970-01-01
  • 2015-10-17
  • 1970-01-01
  • 2018-06-22
相关资源
最近更新 更多