2009-08-27 6 views
0

J'essaie de gérer manuellement certaines colonnes géométriques (spatiales) dans un modèle de rails.Comment empêcher les rails d'échapper des valeurs dans SQL pour une colonne particulière?

Lors de la mise à jour de la colonne de géométrie, je le fais dans des rails:

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

Quelle est la valeur que je veux être dans les mises à jour SQL et ainsi être évaluées par la base de données. Cependant au moment où cela a été à travers la magie de l'enregistrement actif, il sort comme:

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

En d'autres termes, les guillemets sont échappés. C'est bien pour les autres colonnes car cela empêche l'injection SQL, mais pas pour ça. Les valeurs sont garantis flotteurs, et je veux la mise à jour ressembler à:

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

est-il donc un moyen de mettre hors échapper pour une colonne particulière? Ou une meilleure façon de le faire? (J'ai essayé d'utiliser GeoRuby + adaptateur spatial, et adaptateur spatial semble trop bogué à moi, plus je n'ai pas besoin de toutes les fonctionnalités - donc essayer de le faire directement).

+0

Je ne sais pas exactement quel est le problème ici. Si ces guillemets n'étaient pas échappés, vous obtiendriez une erreur SQL en raison de guillemets incorrectement fermés. Si vous récupérez les données sauvegardées, les caractères échappés ne doivent pas être présents. –

+0

Bon point sur les guillemets incorrectement fermés. Cependant, je n'ai jamais besoin de récupérer cette valeur - elle est seulement utilisée dans un index spatial. J'essaie d'obtenir l'équivalent de ceci: UPDATE place les ensembles geom = POINTFROMTEXT ('POINT (52,253,20.977') – frankodwyer

+0

une autre façon de le regarder, c'est quand les colonnes lat, lng sont mises à jour, je veux mettre à jour geom. Ma migration pour geom Je fais ce qui suit après avoir ajouté la colonne: exécuter "UPDATE' # {table} 'set geom = POINTFROMTEXT (CONCAT ('POINT (', lat, '', lng, ')'))). J'aime déclencher une mise à jour similaire à chaque fois que lat ou lng est modifié - soit dans un trigger DB ou via des rails.J'utilise actuellement un callback before_save, ce qui entraîne le problème ci-dessus.Je ne sais pas comment définir une base de données déclencher dans une migration – frankodwyer

Répondre

1

Le Rails Spatial Adapter doit implémenter exactement ce dont vous avez besoin. Bien que, avant que je trouve GeoRuby & Adapter Spatial, je faisais ceci:

  • ont deux champs: un champ de texte et un champ réel de la géométrie, sur le modèle
  • Sur un crochet after_save, j'ai couru quelque chose comme ceci:

    Connection.Execute "mise à jour matable set geom_column = # {} text_column où id = # {id}"

Mais la solution ci-dessus était juste un hack, et ce HAV e problèmes supplémentaires: je ne peux pas créer d'index spatial si la colonne admet des valeurs NULL, MySQL ne me laisse pas définir une valeur par défaut sur une colonne géométrique et la méthode save échoue si la colonne géométrie n'a pas de valeur .

J'essaieraient GeoRuby & Adapter Spatial à la place, ou réutiliser une partie de son code (sur mon cas, je considère que l'extraction de la méthode au courant SIG MysqlAdapter#quote à partir du code de l'adaptateur Spatial).

+0

merci, c'est ce que j'ai fini par faire. J'ai trouvé que c'est un peu difficile sur les versions de rails (par exemple, ne semble pas fonctionner sur le dernier quand j'ai essayé mais était ok sur 2.3.2), mais quand ça marche, ça fait l'affaire. – frankodwyer

+0

La quantité de trucs de vérification de la version rails sur le code de l'Adaptateur Spatial était la raison pour laquelle j'ai choisi de simplement copier le code MysqlAdapter.quote au lieu d'essayer d'utiliser tout le module. :) – ehabkost

1
  1. Vous pouvez utiliser une méthode after_save, écrivez-les avec un appel SQL UPDATE direct. Agaçant, mais devrait fonctionner.

  2. Vous devriez pouvoir créer un déclencheur dans votre migration DB en utilisant la méthode 'execute' ... mais je ne l'ai jamais essayé.

  3. Creusez dans la fonction de calcul d'ActiveRecord: max/min/moy, etc. Vous ne savez pas si cela vous permet d'économiser beaucoup sur l'appel SQL direct dans after_save. Voir les calculs.rb.

  4. Vous pouvez patcher la fonction qui cite les attributs (en recherchant POINTFROMTEXT, puis ignorer la citation). C'est assez facile à trouver, car toutes les méthodes commencent par citation. Commencez par ActiveRecord :: Base #quote_value.

+0

Merci d'avoir essayé la méthode du trigger, mais cela ne semble pas fonctionner - quelque chose dans mysql rebondit sur la mise à jour avant que le trigger ne soit appelé il semble que j'ai revisité l'adaptateur spatial maintenant mais est sensible à la version rails (et peut-être aussi la version mysql - besoin de faire plus de tests) – frankodwyer

+1

Oh et after_save ne fonctionneront probablement pas, puisque les rails tentent d'abord d'écrire une valeur NULL sur geom, ce qui échoue car il y a une contrainte non nulle sur geom. Il faudrait donc d'une manière ou d'une autre empêcher les rails de mettre à jour cet attribut lui-même en premier. – frankodwyer

Questions connexes