2009-08-27 4 views
0

私は、レールモデルのいくつかのジオメトリ(空間)列を手動で管理しようとしています。ジオメトリ列を更新する場合特定の列のSQLでレールがエスケープするのを止める方法を教えてください。

私はレールでこれを行う:

私はSQLの更新になりたいので、データベースによって評価された値である
self.geom="POINTFROMTEXT('POINT(#{lat},#{lng})')" 

。しかし、これは、アクティブなレコードの魔法を経た時点で、それはのように出てくる:つまり

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

、引用符がエスケープされています。 SQLインジェクションを防止するので、これは他のカラムでは問題ありません。値は浮動小数点数であることが保証され、私は更新が見えるようにしたいされています

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

だから、特定の列のためにオフエスケープ有効にする方法はありますか?これを行うより良い方法は?

(私は、私にはあまりにもバグのようで、プラス私は、すべての機能を必要としない+空間アダプタ、および空間的なアダプタをGeoRubyを使用して試してみた - ので、直接それをやろうとしています)。

+0

私はこの問題が何であるかについてはあまりよく分かりません。これらの引用符がエスケープされなかった場合、引用符が正しくないためにSQLエラーが発生します。保存されたデータを取得する場合、エスケープされた文字は表示されません。 –

+0

誤って閉じられた引用符についての良い点。しかし、私はこの値を取得する必要はありません。空間インデックスでのみ使用されます。私はこれに相当するものを取得しようとしています:更新geom = POINTFROMTEXT( 'POINT(52,253,20.977') – frankodwyer

+0

それを見て別の方法は、lat、lng列が更新されるたびに、私はgeomを更新したいです。私の移行のgeom私は列を追加した後、次のようにします: "update##{table}' set geom = POINTFROMTEXT(CONCAT( 'POINT('、lat、 ''、lng、 ')')) " DBトリガーやレール経由で、latやlngが変更されたときにも、同様の更新をトリガーしたいのですが、私は現在before_saveコールバックを使用していますので、上記の問題が発生します。 – frankodwyer

答えて

1

Rails Spatial Adapterは、必要なものを正確に実装する必要があります。私はGeoRuby &空間アダプタを見つけた前に、私はこれをやっていた、けれども:

  • 2つのフィールド有無:after_saveフックでモデル
  • に、1つのテキストフィールドと実際のジオメトリフィールドを、私は次のように走りましたこれ:

    connection.execute "更新MYTABLEセットgeom_column ID =#{ID} =#{text_column}"

しかし、上記溶液がちょうどハックであり、このHAV Eその他の問題:列がNULL値を許可する場合、私は空間インデックスを作成することはできません、MySQLは私がジオメトリ列にデフォルト値を設定することはできませんし、ジオメトリ列に値が設定されていない場合save方法が失敗しました。

代わりにGeoRuby &空間アダプターを試してみるか、コードの一部を再利用します(私の場合は、空間アダプターコードからGIS対応のMysqlAdapter#quoteメソッドのみを抽出することを検討しています)。

+0

ありがとう、これは私がやっていることです。私はレールバージョンについて少し戸惑うことがあることを発見しました(例えば、試したときにはうまくいかなかったようでしたが、2.3.2でOKでした)が、それがうまくいきます。 – frankodwyer

+0

空間アダプタコードでのレールバージョンチェックトリッキーの量は、モジュール全体を使用するのではなく、MysqlAdapter.quoteコードをコピーするだけの理由でした。 :) – ehabkost

1
  1. after_saveメソッドを使用すると、直接SQL UPDATE呼び出しで書き込むことができます。迷惑ですが、うまくいくはずです。

  2. 'execute'メソッドを使用してDB移行でトリガーを作成することはできますが、試したことはありません。

  3. これは、ActiveRecordの計算機能を最大/最小/平均などで掘り下げます。これにより、after_saveで直接SQL呼び出しよりも多くのデータを保存するかどうかはわかりません。 calculations.rbを参照してください。

  4. あなたが属性を引用機能にパッチを適用でき(POINTFROMTEXTを探して、次に引用をスキップ)。すべてのメソッドが引用符で始まるので、これは簡単に見つけることができます。 ActiveRecord :: Base#quote_valueで始まります。

+0

ありがとう。私は実際にトリガメソッドを試しましたが、動作していないようです - トリガが呼び出される前に、mysqlの何かが更新をバウンスします。私は空間アダプタを再訪しました。しかし、レールのバージョン(と多分mysqlのバージョン - より多くのテストを行う必要があります)に敏感です – frankodwyer

+1

ああ、after_saveはおそらく箱から出てこないでしょう。まず、レールがgeomにNULLを書き込もうとします。これはgeomにnullでない制約があるため失敗します。だからレールがその属性自体を最初に更新しないようにする必要があります。 – frankodwyer

関連する問題